Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

Plugin/Wildcard Search

nchernoff

Administrator
May
42
2
Staff member
Most of the time 4NT and Take Command handles files and almost all file handling commands accept wild card searches. For this 4NT and Take Command have a more powerful pattern matcher then the one used by Windows. The following Ada example show how to use 4NT and Take Command wild cards in your plug-in.

Description

The description — unlike the source below — is "work in progress" and not yet finished.

Line 119 — 120

The procedure takes a string with a search pattern of the type dir/pattern &ndash with both dir and pattern beeing optional and a call back function which will be called for each file found.

Line 122 — 123

Commented out is the function entry and exit trace which can be used for debuggin purpouse. Commented out since the function has no known bugs.

Line 125 — 127

In order to perform a wild card search we have to separate the directoy from the pattern. Since a directory in Windows NT can be 215 utf-16 characters in size a static sized buffer is not appropiate and we first determine the lenght needed.

Then we define two variables to hold the directory and pattern part. If you use C check if your C compiler supports alloca – It will make things easier for you. If you use Delphi you will need bite the bullet and use heap memory.

Line 135 — 136

As mentioned we are now going to split the directory and the file name. We employ two function from the TcmdLib for this.

Line 139 — 146

In case there has been no pattern we change the pattern to "*" – all files.

Line 153 — 157

Since we want to use the wild card matcher from the TcmdLib we request all files from directory to match them against the pattern. The Win32.Winbase.FindFirstFileW functions returns a handle for further searches and the first result.

Line 159 — 166

When the handle returned was not valid we raise an exception. I use a function from my trace library so additinal trace info is written when trace is active.

Line 169 — 173

We use the TcmdLib to find out if the current file is a match enableing fBrackets to patterns like [0-9] are matched.

Line 174

The code was formated automaticly using gnat pretty which works well most of the time but sometimes leaves stange artefacts like this loonly 0.

Line 176 — 177

We call the call back procedure for the file found. The call back function will perform any further action we desire. We also increase the file counter by one.

Line 179 — 182

The Win32.Winbase.FindNextFileW will get the next match or return Win32.FALSE if there is not further match – in which case we leave the loop.

Line 187 — 193

If no file was found we raise an exeption with the error message "No Files found.".

Line 187 — 194

We are finished and return to the calling function or procedure.

Ada Code

One could probably use use clauses and refrain from using named parameters to make the code smaller - but I am more into readability then dense coding.

Code:
118    procedure Wildcard_Search
119      (Directory_Pattern : in Win32.WCHAR_Array;
120       Process           : not null access procedure (Directory_Entry : in Win32.WCHAR_Array))
121    is
122       --  Trace : constant TakeCmd.Trace.Object := TakeCmd.Trace.Function_Trace
123       --  (TakeCmd.Trace.Entity); pragma Unreferenced (Trace);
124
125       Directory_Length : constant Interfaces.C.int := PathLength (Directory_Pattern);
126       Directory        : aliased Win32.WCHAR_Array (1 .. Integer (Directory_Length) + 1);
127       Pattern          : aliased File_Name;
128       Dummy            : Win32.PWSTR;
129       Files_Found      : Natural                   := 0;
130
131       pragma Warnings (Off, Dummy);
132       pragma Warnings (Off, Directory);
133       pragma Warnings (Off, Pattern);
134    begin
135       Dummy := PathPart (pszName => Directory_Pattern, pszPath => Win32.Addr (Directory));
136       Dummy :=
137          FilenamePart (pszName => Directory_Pattern, pszFilenamePart => Win32.Addr (Pattern));
138
139       Fix_Pattern : declare
140          Pattern_Length : constant Interfaces.C.int :=
141             Win32.Winbase.lstrlenW (Win32.Addr (Pattern));
142       begin
143          if Pattern_Length = 0 then
144             Pattern := (1 => '*', others => Win32.Wide_Nul);
145          end if;
146       end Fix_Pattern;
147
148       Find_Files : declare
149          use type Win32.Winnt.HANDLE;
150          use type Win32.BOOL;
151
152          Data   : aliased Win32.Winbase.WIN32_FIND_DATAW;
153          Handle : constant Win32.Winnt.HANDLE :=
154             Win32.Winbase.FindFirstFileW
155               (lpFileName     =>
156                   Win32.Addr (Directory (1 .. Directory'Last - 1) & "*" & Win32.Wide_Nul),
157                lpFindFileData => Data'Unchecked_Access);
158       begin
159          if Handle = Win32.Winbase.INVALID_HANDLE_VALUE then
160            TakeCmd.Trace.Raise_Exception
161               (Raising => Win32_Error'Identity,
162                Message => ": FindFirstFileW: " &
163                           Win32.DWORD'Image (Win32.Winbase.GetLastError) &
164                           ". ",
165                Entity  => TakeCmd.Trace.Entity,
166                Source  => TakeCmd.Trace.Source);
167          else
168             Process_Files : loop
169                if WildcardComparison
170                      (pszWildName => Win32.Addr (Pattern),
171                       pszFileName => Win32.Addr (Data.cFileName),
172                       fExtension  => 0,
173                       fBrackets   => 1) =
174                   0
175                then
176                   Process (Directory (1 .. Directory'Last - 1) & Data.cFileName);
177                   Files_Found := Files_Found + 1;
178                end if;
179                exit Process_Files when Win32.Winbase.FindNextFileW
180                                           (hFindFile      => Handle,
181                                            lpFindFileData => Data'Unchecked_Access) /=
182                                        Win32.TRUE;
183             end loop Process_Files;
184          end if;
185       end Find_Files;
186
187       if Files_Found = 0 then
188          TakeCmd.Trace.Raise_Exception
189            (Raising => Name_Error'Identity,
190             Message => "No Files found.",
191             Entity  => TakeCmd.Trace.Entity,
192             Source  => TakeCmd.Trace.Source);
193       end if;
194       return;
195    end Wildcard_Search;
 
Back
Top