OSDN Git Service

Delete all lines containing "$Revision:".
[pf3gnuchains/gcc-fork.git] / gcc / ada / g-diopit.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --  G N A T . D I R E C T O R Y _ O P E R A T I O N S . I T E R A T I O N   --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --                                                                          --
10 --            Copyright (C) 2001 Ada Core Technologies, Inc.                --
11 --                                                                          --
12 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
13 -- terms of the  GNU General Public License as published  by the Free Soft- --
14 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
15 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
18 -- for  more details.  You should have  received  a copy of the GNU General --
19 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
20 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
21 -- MA 02111-1307, USA.                                                      --
22 --                                                                          --
23 -- As a special exception,  if other files  instantiate  generics from this --
24 -- unit, or you link  this unit with other files  to produce an executable, --
25 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
26 -- covered  by the  GNU  General  Public  License.  This exception does not --
27 -- however invalidate  any other reasons why  the executable file  might be --
28 -- covered by the  GNU Public License.                                      --
29 --                                                                          --
30 -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com).   --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 with Ada.Characters.Handling;
35 with Ada.Strings.Fixed;
36 with Ada.Strings.Maps;
37 with GNAT.OS_Lib;
38 with GNAT.Regexp;
39
40 package body GNAT.Directory_Operations.Iteration is
41
42    use Ada;
43
44    ----------
45    -- Find --
46    ----------
47
48    procedure Find
49      (Root_Directory : Dir_Name_Str;
50       File_Pattern   : String)
51    is
52       File_Regexp : constant Regexp.Regexp := Regexp.Compile (File_Pattern);
53       Index       : Natural := 0;
54
55       procedure Read_Directory (Directory : Dir_Name_Str);
56       --  Open Directory and read all entries. This routine is called
57       --  recursively for each sub-directories.
58
59       function Make_Pathname (Dir, File : String) return String;
60       --  Returns the pathname for File by adding Dir as prefix.
61
62       -------------------
63       -- Make_Pathname --
64       -------------------
65
66       function Make_Pathname (Dir, File : String) return String is
67       begin
68          if Dir (Dir'Last) = '/' or else Dir (Dir'Last) = '\' then
69             return Dir & File;
70          else
71             return Dir & Dir_Separator & File;
72          end if;
73       end Make_Pathname;
74
75       --------------------
76       -- Read_Directory --
77       --------------------
78
79       procedure Read_Directory (Directory : Dir_Name_Str) is
80          Dir    : Dir_Type;
81          Buffer : String (1 .. 2_048);
82          Last   : Natural;
83          Quit   : Boolean;
84
85       begin
86          Open (Dir, Directory);
87
88          loop
89             Read (Dir, Buffer, Last);
90             exit when Last = 0;
91
92             declare
93                Dir_Entry : constant String := Buffer (1 .. Last);
94                Pathname  : constant String
95                  := Make_Pathname (Directory, Dir_Entry);
96             begin
97                if Regexp.Match (Dir_Entry, File_Regexp) then
98                   Quit  := False;
99                   Index := Index + 1;
100
101                   begin
102                      Action (Pathname, Index, Quit);
103                   exception
104                      when others =>
105                         Close (Dir);
106                         raise;
107                   end;
108
109                   exit when Quit;
110                end if;
111
112                --  Recursively call for sub-directories, except for . and ..
113
114                if not (Dir_Entry = "." or else Dir_Entry = "..")
115                  and then OS_Lib.Is_Directory (Pathname)
116                then
117                   Read_Directory (Pathname);
118                end if;
119             end;
120          end loop;
121
122          Close (Dir);
123       end Read_Directory;
124
125    begin
126       Read_Directory (Root_Directory);
127    end Find;
128
129    -----------------------
130    -- Wildcard_Iterator --
131    -----------------------
132
133    procedure Wildcard_Iterator (Path : Path_Name) is
134
135       Index : Natural := 0;
136
137       procedure Read
138         (Directory      : String;
139          File_Pattern   : String;
140          Suffix_Pattern : String);
141       --  Read entries in Directory and call user's callback if the entry
142       --  match File_Pattern and Suffix_Pattern is empty otherwise it will go
143       --  down one more directory level by calling Next_Level routine above.
144
145       procedure Next_Level
146         (Current_Path : String;
147          Suffix_Path  : String);
148       --  Extract next File_Pattern from Suffix_Path and call Read routine
149       --  above.
150
151       ----------------
152       -- Next_Level --
153       ----------------
154
155       procedure Next_Level
156         (Current_Path : String;
157          Suffix_Path  : String)
158       is
159          DS : Natural;
160          SP : String renames Suffix_Path;
161
162       begin
163          if SP'Length > 2
164            and then SP (SP'First) = '.'
165            and then Strings.Maps.Is_In (SP (SP'First + 1), Dir_Seps)
166          then
167             --  Starting with "./"
168
169             DS := Strings.Fixed.Index
170               (SP (SP'First + 2 .. SP'Last),
171                Dir_Seps);
172
173             if DS = 0 then
174
175                --  We have "./"
176
177                Read (Current_Path & ".", "*", "");
178
179             else
180                --  We have "./dir"
181
182                Read (Current_Path & ".",
183                      SP (SP'First + 2 .. DS - 1),
184                      SP (DS .. SP'Last));
185             end if;
186
187          elsif SP'Length > 3
188            and then SP (SP'First .. SP'First + 1) = ".."
189            and then Strings.Maps.Is_In (SP (SP'First + 2), Dir_Seps)
190          then
191             --  Starting with "../"
192
193             DS := Strings.Fixed.Index
194               (SP (SP'First + 3 .. SP'Last),
195                Dir_Seps);
196
197             if DS = 0 then
198
199                --  We have "../"
200
201                Read (Current_Path & "..", "*", "");
202
203             else
204                --  We have "../dir"
205
206                Read (Current_Path & "..",
207                      SP (SP'First + 4 .. DS - 1),
208                      SP (DS .. SP'Last));
209             end if;
210
211          elsif Current_Path = ""
212            and then SP'Length > 1
213            and then Characters.Handling.Is_Letter (SP (SP'First))
214            and then SP (SP'First + 1) = ':'
215          then
216             --  Starting with "<drive>:"
217
218             if SP'Length > 2
219               and then Strings.Maps.Is_In (SP (SP'First + 2), Dir_Seps)
220             then
221                --  Starting with "<drive>:\"
222
223                DS :=  Strings.Fixed.Index
224                         (SP (SP'First + 3 .. SP'Last), Dir_Seps);
225
226                if DS = 0 then
227
228                   --  Se have "<drive>:\dir"
229
230                   Read (SP (SP'First .. SP'First + 1),
231                         SP (SP'First + 3 .. SP'Last),
232                         "");
233
234                else
235                   --  We have "<drive>:\dir\kkk"
236
237                   Read (SP (SP'First .. SP'First + 1),
238                         SP (SP'First + 3 .. DS - 1),
239                         SP (DS .. SP'Last));
240                end if;
241
242             else
243                --  Starting with "<drive>:"
244
245                DS :=  Strings.Fixed.Index
246                         (SP (SP'First + 2 .. SP'Last), Dir_Seps);
247
248                if DS = 0 then
249
250                   --  We have "<drive>:dir"
251
252                   Read (SP (SP'First .. SP'First + 1),
253                         SP (SP'First + 2 .. SP'Last),
254                         "");
255
256                else
257                   --  We have "<drive>:dir/kkk"
258
259                   Read (SP (SP'First .. SP'First + 1),
260                         SP (SP'First + 2 .. DS - 1),
261                         SP (DS .. SP'Last));
262                end if;
263
264             end if;
265
266          elsif Strings.Maps.Is_In (SP (SP'First), Dir_Seps) then
267
268             --  Starting with a /
269
270             DS := Strings.Fixed.Index
271               (SP (SP'First + 1 .. SP'Last),
272                Dir_Seps);
273
274             if DS = 0 then
275
276                --  We have "/dir"
277
278                Read (Current_Path,
279                      SP (SP'First + 1 .. SP'Last),
280                      "");
281             else
282                --  We have "/dir/kkk"
283
284                Read (Current_Path,
285                      SP (SP'First + 1 .. DS - 1),
286                      SP (DS .. SP'Last));
287             end if;
288
289          else
290             --  Starting with a name
291
292             DS := Strings.Fixed.Index (SP, Dir_Seps);
293
294             if DS = 0 then
295
296                --  We have "dir"
297
298                Read (Current_Path & '.',
299                      SP,
300                      "");
301             else
302                --  We have "dir/kkk"
303
304                Read (Current_Path & '.',
305                      SP (SP'First .. DS - 1),
306                      SP (DS .. SP'Last));
307             end if;
308
309          end if;
310       end Next_Level;
311
312       ----------
313       -- Read --
314       ----------
315
316       Quit : Boolean := False;
317       --  Global state to be able to exit all recursive calls.
318
319       procedure Read
320         (Directory      : String;
321          File_Pattern   : String;
322          Suffix_Pattern : String)
323       is
324          File_Regexp : constant Regexp.Regexp :=
325                          Regexp.Compile (File_Pattern, Glob => True);
326          Dir    : Dir_Type;
327          Buffer : String (1 .. 2_048);
328          Last   : Natural;
329
330       begin
331          if OS_Lib.Is_Directory (Directory) then
332             Open (Dir, Directory);
333
334             Dir_Iterator : loop
335                Read (Dir, Buffer, Last);
336                exit Dir_Iterator when Last = 0;
337
338                declare
339                   Dir_Entry : constant String := Buffer (1 .. Last);
340                   Pathname  : constant String :=
341                                 Directory & Dir_Separator & Dir_Entry;
342                begin
343                   --  Handle "." and ".." only if explicit use in the
344                   --  File_Pattern.
345
346                   if not
347                     ((Dir_Entry = "." and then File_Pattern /= ".")
348                        or else
349                      (Dir_Entry = ".." and then File_Pattern /= ".."))
350                   then
351                      if Regexp.Match (Dir_Entry, File_Regexp) then
352
353                         if Suffix_Pattern = "" then
354
355                            --  No more matching needed, call user's callback
356
357                            Index := Index + 1;
358
359                            begin
360                               Action (Pathname, Index, Quit);
361
362                            exception
363                               when others =>
364                                  Close (Dir);
365                                  raise;
366                            end;
367
368                            exit Dir_Iterator when Quit;
369
370                         else
371                            --  Down one level
372
373                            Next_Level
374                              (Directory & Dir_Separator & Dir_Entry,
375                               Suffix_Pattern);
376                         end if;
377                      end if;
378                   end if;
379                end;
380
381                exit Dir_Iterator when Quit;
382
383             end loop Dir_Iterator;
384
385             Close (Dir);
386          end if;
387       end Read;
388
389    begin
390       Next_Level ("", Path);
391    end Wildcard_Iterator;
392
393 end GNAT.Directory_Operations.Iteration;