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.
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;