OSDN Git Service

* stor-layout.c (initialize_sizetypes): Set SIZETYPE earlier,
[pf3gnuchains/gcc-fork.git] / gcc / ada / g-comlin.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                    G N A T . C O M M A N D _ L I N E                     --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1999-2004 Free Software Foundation, Inc.          --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, USA.                                                      --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNAT was originally developed  by the GNAT team at  New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 with Ada.Command_Line;
35 with GNAT.OS_Lib; use GNAT.OS_Lib;
36
37 package body GNAT.Command_Line is
38
39    package CL renames Ada.Command_Line;
40
41    type Section_Number is new Natural range 0 .. 65534;
42    for Section_Number'Size use 16;
43
44    type Parameter_Type is record
45       Arg_Num : Positive;
46       First   : Positive;
47       Last    : Positive;
48    end record;
49    The_Parameter : Parameter_Type;
50    The_Switch    : Parameter_Type;
51    --  This type and this variable are provided to store the current switch
52    --  and parameter
53
54    type Is_Switch_Type is array (1 .. CL.Argument_Count) of Boolean;
55    pragma Pack (Is_Switch_Type);
56
57    Is_Switch : Is_Switch_Type := (others => False);
58    --  Indicates wich arguments on the command line are considered not be
59    --  switches or parameters to switches (this leaves e.g. the filenames...)
60
61    type Section_Type is array (1 .. CL.Argument_Count + 1) of Section_Number;
62    pragma Pack (Section_Type);
63    Section : Section_Type := (others => 1);
64    --  Contains the number of the section associated with the current
65    --  switch.  If this number is 0, then it is a section delimiter, which
66    --  is never returns by GetOpt.
67    --  The last element of this array is set to 0 to avoid the need to test for
68    --  if we have reached the end of the command line in loops.
69
70    Current_Argument : Natural := 1;
71    --  Number of the current argument parsed on the command line
72
73    Current_Index : Natural := 1;
74    --  Index in the current argument of the character to be processed
75
76    Current_Section : Section_Number := 1;
77
78    Expansion_It : aliased Expansion_Iterator;
79    --  When Get_Argument is expanding a file name, this is the iterator used
80
81    In_Expansion : Boolean := False;
82    --  True if we are expanding a file
83
84    Switch_Character : Character := '-';
85    --  The character at the beginning of the command line arguments,
86    --  indicating the beginning of a switch
87
88    Stop_At_First : Boolean := False;
89    --  If it is True then Getopt stops at the first non-switch argument
90
91    procedure Set_Parameter
92      (Variable : out Parameter_Type;
93       Arg_Num  : Positive;
94       First    : Positive;
95       Last     : Positive);
96    pragma Inline (Set_Parameter);
97    --  Set the parameter that will be returned by Parameter below
98
99    function Goto_Next_Argument_In_Section return Boolean;
100    --  Go to the next argument on the command line. If we are at the end
101    --  of the current section, we want to make sure there is no other
102    --  identical section on the command line (there might be multiple
103    --  instances of -largs). Returns True iff there is another argument.
104
105    function Get_File_Names_Case_Sensitive return Integer;
106    pragma Import (C, Get_File_Names_Case_Sensitive,
107                   "__gnat_get_file_names_case_sensitive");
108    File_Names_Case_Sensitive : constant Boolean :=
109                                  Get_File_Names_Case_Sensitive /= 0;
110
111    procedure Canonical_Case_File_Name (S : in out String);
112    --  Given a file name, converts it to canonical case form. For systems
113    --  where file names are case sensitive, this procedure has no effect.
114    --  If file names are not case sensitive (i.e. for example if you have
115    --  the file "xyz.adb", you can refer to it as XYZ.adb or XyZ.AdB), then
116    --  this call converts the given string to canonical all lower case form,
117    --  so that two file names compare equal if they refer to the same file.
118
119    ------------------------------
120    -- Canonical_Case_File_Name --
121    ------------------------------
122
123    procedure Canonical_Case_File_Name (S : in out String) is
124    begin
125       if not File_Names_Case_Sensitive then
126          for J in S'Range loop
127             if S (J) in 'A' .. 'Z' then
128                S (J) := Character'Val (
129                           Character'Pos (S (J)) +
130                           Character'Pos ('a')   -
131                           Character'Pos ('A'));
132             end if;
133          end loop;
134       end if;
135    end Canonical_Case_File_Name;
136
137    ---------------
138    -- Expansion --
139    ---------------
140
141    function Expansion (Iterator : Expansion_Iterator) return String is
142       use GNAT.Directory_Operations;
143       type Pointer is access all Expansion_Iterator;
144
145       S    : String (1 .. 1024);
146       Last : Natural;
147       It   : constant Pointer := Iterator'Unrestricted_Access;
148
149       Current : Depth := It.Current_Depth;
150       NL      : Positive;
151
152    begin
153       --  It is assumed that a directory is opened at the current level;
154       --  otherwise, GNAT.Directory_Operations.Directory_Error will be raised
155       --  at the first call to Read.
156
157       loop
158          Read (It.Levels (Current).Dir, S, Last);
159
160          --  If we have exhausted the directory, close it and go back one level
161
162          if Last = 0 then
163             Close (It.Levels (Current).Dir);
164
165             --  If we are at level 1, we are finished; return an empty string.
166
167             if Current = 1 then
168                return String'(1 .. 0 => ' ');
169             else
170                --  Otherwise, continue with the directory at the previous level
171
172                Current := Current - 1;
173                It.Current_Depth := Current;
174             end if;
175
176          --  If this is a directory, that is neither "." or "..", attempt to
177          --  go to the next level.
178
179          elsif Is_Directory
180            (It.Dir_Name (1 .. It.Levels (Current).Name_Last) & S (1 .. Last))
181            and then S (1 .. Last) /= "."
182            and then S (1 .. Last) /= ".."
183          then
184             --  We can go to the next level only if we have not reached the
185             --  maximum depth,
186
187             if Current < It.Maximum_Depth then
188                NL := It.Levels (Current).Name_Last;
189
190                --  And if relative path of this new directory is not too long
191
192                if NL + Last + 1 < Max_Path_Length then
193                   Current := Current + 1;
194                   It.Current_Depth := Current;
195                   It.Dir_Name (NL + 1 .. NL + Last) := S (1 .. Last);
196                   NL := NL + Last + 1;
197                   It.Dir_Name (NL) := Directory_Separator;
198                   It.Levels (Current).Name_Last := NL;
199                   Canonical_Case_File_Name (It.Dir_Name (1 .. NL));
200
201                   --  Open the new directory, and read from it
202
203                   GNAT.Directory_Operations.Open
204                     (It.Levels (Current).Dir, It.Dir_Name (1 .. NL));
205                end if;
206             end if;
207
208          --  If not a directory, check the relative path against the pattern
209
210          else
211             declare
212                Name : String :=
213                  It.Dir_Name (It.Start .. It.Levels (Current).Name_Last) &
214                  S (1 .. Last);
215             begin
216                Canonical_Case_File_Name (Name);
217
218                --  If it matches, return the relative path
219
220                if GNAT.Regexp.Match (Name, Iterator.Regexp) then
221                   return Name;
222                end if;
223             end;
224          end if;
225
226       end loop;
227
228       return String'(1 .. 0 => ' ');
229    end Expansion;
230
231    -----------------
232    -- Full_Switch --
233    -----------------
234
235    function Full_Switch return String is
236    begin
237       return CL.Argument (The_Switch.Arg_Num)
238         (The_Switch.First .. The_Switch.Last);
239    end Full_Switch;
240
241    ------------------
242    -- Get_Argument --
243    ------------------
244
245    function Get_Argument (Do_Expansion : Boolean := False) return String is
246       Total : constant Natural := CL.Argument_Count;
247
248    begin
249       if In_Expansion then
250          declare
251             S : constant String := Expansion (Expansion_It);
252
253          begin
254             if S'Length /= 0 then
255                return S;
256             else
257                In_Expansion := False;
258             end if;
259          end;
260       end if;
261
262       if Current_Argument > Total then
263
264          --  If this is the first time this function is called
265
266          if Current_Index = 1 then
267             Current_Argument := 1;
268             while Current_Argument <= CL.Argument_Count
269               and then Section (Current_Argument) /= Current_Section
270             loop
271                Current_Argument := Current_Argument + 1;
272             end loop;
273          else
274             return String'(1 .. 0 => ' ');
275          end if;
276
277       elsif Section (Current_Argument) = 0 then
278          while Current_Argument <= CL.Argument_Count
279            and then Section (Current_Argument) /= Current_Section
280          loop
281             Current_Argument := Current_Argument + 1;
282          end loop;
283       end if;
284
285       Current_Index := 2;
286
287       while Current_Argument <= Total
288         and then Is_Switch (Current_Argument)
289       loop
290          Current_Argument := Current_Argument + 1;
291       end loop;
292
293       if Current_Argument > Total then
294          return String'(1 .. 0 => ' ');
295       end if;
296
297       if Section (Current_Argument) = 0 then
298          return Get_Argument (Do_Expansion);
299       end if;
300
301       Current_Argument := Current_Argument + 1;
302
303       --  Could it be a file name with wild cards to expand?
304
305       if Do_Expansion then
306          declare
307             Arg       : String renames CL.Argument (Current_Argument - 1);
308             Index     : Positive := Arg'First;
309
310          begin
311             while Index <= Arg'Last loop
312
313                if Arg (Index) = '*'
314                  or else Arg (Index) = '?'
315                  or else Arg (Index) = '['
316                then
317                   In_Expansion := True;
318                   Start_Expansion (Expansion_It, Arg);
319                   return Get_Argument (Do_Expansion);
320                end if;
321
322                Index := Index + 1;
323             end loop;
324          end;
325       end if;
326
327       return CL.Argument (Current_Argument - 1);
328    end Get_Argument;
329
330    ------------
331    -- Getopt --
332    ------------
333
334    function Getopt
335      (Switches    : String;
336       Concatenate : Boolean := True) return Character
337    is
338       Dummy : Boolean;
339       pragma Unreferenced (Dummy);
340
341    begin
342       --  If we have finished parsing the current command line item (there
343       --  might be multiple switches in a single item), then go to the next
344       --  element
345
346       if Current_Argument > CL.Argument_Count
347         or else (Current_Index > CL.Argument (Current_Argument)'Last
348                    and then not Goto_Next_Argument_In_Section)
349       then
350          return ASCII.NUL;
351       end if;
352
353       --  If we are on a new item, test if this might be a switch
354
355       if Current_Index = 1 then
356          if CL.Argument (Current_Argument)(1) /= Switch_Character then
357             if Switches (Switches'First) = '*' then
358                Set_Parameter (The_Switch,
359                               Arg_Num => Current_Argument,
360                               First   => 1,
361                               Last    => CL.Argument (Current_Argument)'Last);
362                Is_Switch (Current_Argument) := True;
363                Dummy := Goto_Next_Argument_In_Section;
364                return '*';
365             end if;
366
367             if Stop_At_First then
368                Current_Argument := Positive'Last;
369                return ASCII.NUL;
370
371             elsif not Goto_Next_Argument_In_Section then
372                return ASCII.NUL;
373
374             else
375                return Getopt (Switches);
376             end if;
377          end if;
378
379          Current_Index := 2;
380          Is_Switch (Current_Argument) := True;
381       end if;
382
383       declare
384          Arg            : String renames CL.Argument (Current_Argument);
385          Index_Switches : Natural := 0;
386          Max_Length     : Natural := 0;
387          Index          : Natural := Switches'First;
388          Length         : Natural := 1;
389          End_Index      : Natural;
390
391       begin
392          while Index <= Switches'Last loop
393
394             --  Search the length of the parameter at this position in Switches
395
396             Length := Index;
397             while Length <= Switches'Last
398               and then Switches (Length) /= ' '
399             loop
400                Length := Length + 1;
401             end loop;
402
403             if (Switches (Length - 1) = ':'  or else
404                 Switches (Length - 1) = '='  or else
405                 Switches (Length - 1) = '?'  or else
406                 Switches (Length - 1) = '!')
407               and then Length > Index + 1
408             then
409                Length := Length - 1;
410             end if;
411
412             --  If it is the one we searched, it may be a candidate
413
414             if Current_Index + Length - 1 - Index <= Arg'Last
415               and then
416                 Switches (Index .. Length - 1) =
417                   Arg (Current_Index .. Current_Index + Length - 1 - Index)
418               and then Length - Index > Max_Length
419             then
420                Index_Switches := Index;
421                Max_Length     := Length - Index;
422             end if;
423
424             --  Look for the next switch in Switches
425
426             while Index <= Switches'Last
427               and then Switches (Index) /= ' ' loop
428                Index := Index + 1;
429             end loop;
430
431             Index := Index + 1;
432          end loop;
433
434          End_Index := Current_Index + Max_Length - 1;
435
436          --  If switch is not accepted, skip it, unless we had '*' in Switches
437
438          if Index_Switches = 0 then
439             if Switches (Switches'First) = '*' then
440                Set_Parameter (The_Switch,
441                               Arg_Num => Current_Argument,
442                               First   => 1,
443                               Last    => CL.Argument (Current_Argument)'Last);
444                Is_Switch (Current_Argument) := True;
445                Dummy := Goto_Next_Argument_In_Section;
446                return '*';
447             end if;
448
449             --  Depending on the value of Concatenate, the full switch is
450             --  a single character (True) or the rest of the argument (False).
451
452             if Concatenate then
453                End_Index := Current_Index;
454             else
455                End_Index := Arg'Last;
456             end if;
457
458             Set_Parameter (The_Switch,
459                            Arg_Num => Current_Argument,
460                            First   => Current_Index,
461                            Last    => End_Index);
462             Current_Index := End_Index + 1;
463             raise Invalid_Switch;
464          end if;
465
466          Set_Parameter (The_Switch,
467                         Arg_Num => Current_Argument,
468                         First   => Current_Index,
469                         Last    => End_Index);
470
471          --  Case of switch needs an argument
472
473          if Index_Switches + Max_Length <= Switches'Last then
474
475             case Switches (Index_Switches + Max_Length) is
476
477                when ':' =>
478
479                   if End_Index < Arg'Last then
480                      Set_Parameter (The_Parameter,
481                                     Arg_Num => Current_Argument,
482                                     First   => End_Index + 1,
483                                     Last    => Arg'Last);
484                      Dummy := Goto_Next_Argument_In_Section;
485
486                   elsif Section (Current_Argument + 1) /= 0 then
487                      Set_Parameter
488                        (The_Parameter,
489                         Arg_Num => Current_Argument + 1,
490                         First   => 1,
491                         Last    => CL.Argument (Current_Argument + 1)'Last);
492                      Current_Argument := Current_Argument + 1;
493                      Is_Switch (Current_Argument) := True;
494                      Dummy := Goto_Next_Argument_In_Section;
495
496                   else
497                      Current_Index := End_Index + 1;
498                      raise Invalid_Parameter;
499                   end if;
500
501                when '=' =>
502
503                   --  If the switch is of the form <switch>=xxx
504
505                   if End_Index < Arg'Last then
506
507                      if Arg (End_Index + 1) = '='
508                        and then End_Index + 1 < Arg'Last
509                      then
510                         Set_Parameter (The_Parameter,
511                                        Arg_Num => Current_Argument,
512                                        First   => End_Index + 2,
513                                        Last    => Arg'Last);
514                         Dummy := Goto_Next_Argument_In_Section;
515
516                      else
517                         Current_Index := End_Index + 1;
518                         raise Invalid_Parameter;
519                      end if;
520
521                   --  If the switch is of the form <switch> xxx
522
523                   elsif Section (Current_Argument + 1) /= 0 then
524                      Set_Parameter
525                        (The_Parameter,
526                         Arg_Num => Current_Argument + 1,
527                         First   => 1,
528                         Last    => CL.Argument (Current_Argument + 1)'Last);
529                      Current_Argument := Current_Argument + 1;
530                      Is_Switch (Current_Argument) := True;
531                      Dummy := Goto_Next_Argument_In_Section;
532
533                   else
534                      Current_Index := End_Index + 1;
535                      raise Invalid_Parameter;
536                   end if;
537
538                when '!' =>
539
540                   if End_Index < Arg'Last then
541                      Set_Parameter (The_Parameter,
542                                     Arg_Num => Current_Argument,
543                                     First   => End_Index + 1,
544                                     Last    => Arg'Last);
545                      Dummy := Goto_Next_Argument_In_Section;
546
547                   else
548                      Current_Index := End_Index + 1;
549                      raise Invalid_Parameter;
550                   end if;
551
552                when '?' =>
553
554                   if End_Index < Arg'Last then
555                      Set_Parameter (The_Parameter,
556                                     Arg_Num => Current_Argument,
557                                     First   => End_Index + 1,
558                                     Last    => Arg'Last);
559
560                   else
561                      Set_Parameter (The_Parameter,
562                                     Arg_Num => Current_Argument,
563                                     First   => 2,
564                                     Last    => 1);
565                   end if;
566                   Dummy := Goto_Next_Argument_In_Section;
567
568                when others =>
569                   if Concatenate or else End_Index = Arg'Last then
570                      Current_Index := End_Index + 1;
571
572                   else
573                      --  If Concatenate is False and the full argument is not
574                      --  recognized as a switch, this is an invalid switch.
575
576                      Set_Parameter (The_Switch,
577                                     Arg_Num => Current_Argument,
578                                     First   => Current_Index,
579                                     Last    => Arg'Last);
580                      Current_Index := Arg'Last + 1;
581                      raise Invalid_Switch;
582                   end if;
583             end case;
584
585          elsif Concatenate or else End_Index = Arg'Last then
586             Current_Index := End_Index + 1;
587
588          else
589             --  If Concatenate is False and the full argument is not
590             --  recognized as a switch, this is an invalid switch.
591
592             Set_Parameter (The_Switch,
593                            Arg_Num => Current_Argument,
594                            First   => Current_Index,
595                            Last    => Arg'Last);
596             Current_Index := Arg'Last + 1;
597             raise Invalid_Switch;
598          end if;
599
600          return Switches (Index_Switches);
601       end;
602    end Getopt;
603
604    -----------------------------------
605    -- Goto_Next_Argument_In_Section --
606    -----------------------------------
607
608    function Goto_Next_Argument_In_Section return Boolean is
609    begin
610       Current_Index := 1;
611       Current_Argument := Current_Argument + 1;
612
613       if Section (Current_Argument) = 0 then
614          loop
615             if Current_Argument > CL.Argument_Count then
616                return False;
617             end if;
618
619             Current_Argument := Current_Argument + 1;
620             exit when Section (Current_Argument) = Current_Section;
621          end loop;
622       end if;
623       return True;
624    end Goto_Next_Argument_In_Section;
625
626    ------------------
627    -- Goto_Section --
628    ------------------
629
630    procedure Goto_Section (Name : String := "") is
631       Index : Integer := 1;
632
633    begin
634       In_Expansion := False;
635
636       if Name = "" then
637          Current_Argument := 1;
638          Current_Index    := 1;
639          Current_Section  := 1;
640          return;
641       end if;
642
643       while Index <= CL.Argument_Count loop
644
645          if Section (Index) = 0
646            and then CL.Argument (Index) = Switch_Character & Name
647          then
648             Current_Argument := Index + 1;
649             Current_Index    := 1;
650
651             if Current_Argument <= CL.Argument_Count then
652                Current_Section := Section (Current_Argument);
653             end if;
654             return;
655          end if;
656
657          Index := Index + 1;
658       end loop;
659
660       Current_Argument := Positive'Last;
661       Current_Index := 2;   --  so that Get_Argument returns nothing
662    end Goto_Section;
663
664    ----------------------------
665    -- Initialize_Option_Scan --
666    ----------------------------
667
668    procedure Initialize_Option_Scan
669      (Switch_Char              : Character := '-';
670       Stop_At_First_Non_Switch : Boolean := False;
671       Section_Delimiters       : String := "")
672    is
673       Section_Num     : Section_Number := 1;
674       Section_Index   : Integer        := Section_Delimiters'First;
675       Last            : Integer;
676       Delimiter_Found : Boolean;
677
678    begin
679       Current_Argument := 0;
680       Current_Index := 0;
681       In_Expansion := False;
682       Switch_Character := Switch_Char;
683       Stop_At_First := Stop_At_First_Non_Switch;
684
685       --  If we are using sections, we have to preprocess the command line
686       --  to delimit them. A section can be repeated, so we just give each
687       --  item on the command line a section number
688
689       while Section_Index <= Section_Delimiters'Last loop
690
691          Last := Section_Index;
692          while Last <= Section_Delimiters'Last
693            and then Section_Delimiters (Last) /= ' '
694          loop
695             Last := Last + 1;
696          end loop;
697
698          Delimiter_Found := False;
699          Section_Num := Section_Num + 1;
700
701          for Index in 1 .. CL.Argument_Count loop
702             if CL.Argument (Index)(1) = Switch_Character
703               and then
704                 CL.Argument (Index) = Switch_Character &
705                                         Section_Delimiters
706                                           (Section_Index .. Last - 1)
707             then
708                Section (Index) := 0;
709                Delimiter_Found := True;
710
711             elsif Section (Index) = 0 then
712                Delimiter_Found := False;
713
714             elsif Delimiter_Found then
715                Section (Index) := Section_Num;
716             end if;
717          end loop;
718
719          Section_Index := Last + 1;
720          while Section_Index <= Section_Delimiters'Last
721            and then Section_Delimiters (Section_Index) = ' '
722          loop
723             Section_Index := Section_Index + 1;
724          end loop;
725       end loop;
726
727       Delimiter_Found := Goto_Next_Argument_In_Section;
728    end Initialize_Option_Scan;
729
730    ---------------
731    -- Parameter --
732    ---------------
733
734    function Parameter return String is
735    begin
736       if The_Parameter.First > The_Parameter.Last then
737          return String'(1 .. 0 => ' ');
738       else
739          return CL.Argument (The_Parameter.Arg_Num)
740            (The_Parameter.First .. The_Parameter.Last);
741       end if;
742    end Parameter;
743
744    -------------------
745    -- Set_Parameter --
746    -------------------
747
748    procedure Set_Parameter
749      (Variable : out Parameter_Type;
750       Arg_Num  : Positive;
751       First    : Positive;
752       Last     : Positive)
753    is
754    begin
755       Variable.Arg_Num := Arg_Num;
756       Variable.First   := First;
757       Variable.Last    := Last;
758    end Set_Parameter;
759
760    ---------------------
761    -- Start_Expansion --
762    ---------------------
763
764    procedure Start_Expansion
765      (Iterator     : out Expansion_Iterator;
766       Pattern      : String;
767       Directory    : String := "";
768       Basic_Regexp : Boolean := True)
769    is
770       Directory_Separator : Character;
771       pragma Import (C, Directory_Separator, "__gnat_dir_separator");
772       First : Positive := Pattern'First;
773
774       Pat : String := Pattern;
775
776    begin
777       Canonical_Case_File_Name (Pat);
778       Iterator.Current_Depth := 1;
779
780       --  If Directory is unspecified, use the current directory ("./" or ".\")
781
782       if Directory = "" then
783          Iterator.Dir_Name (1 .. 2) := "." & Directory_Separator;
784          Iterator.Start := 3;
785
786       else
787          Iterator.Dir_Name (1 .. Directory'Length) := Directory;
788          Iterator.Start := Directory'Length + 1;
789          Canonical_Case_File_Name (Iterator.Dir_Name (1 .. Directory'Length));
790
791          --  Make sure that the last character is a directory separator
792
793          if Directory (Directory'Last) /= Directory_Separator then
794             Iterator.Dir_Name (Iterator.Start) := Directory_Separator;
795             Iterator.Start := Iterator.Start + 1;
796          end if;
797       end if;
798
799       Iterator.Levels (1).Name_Last := Iterator.Start - 1;
800
801       --  Open the initial Directory, at depth 1
802
803       GNAT.Directory_Operations.Open
804         (Iterator.Levels (1).Dir, Iterator.Dir_Name (1 .. Iterator.Start - 1));
805
806       --  If in the current directory and the pattern starts with "./" or ".\",
807       --  drop the "./" or ".\" from the pattern.
808
809       if Directory = "" and then Pat'Length > 2
810         and then Pat (Pat'First) = '.'
811         and then Pat (Pat'First + 1) = Directory_Separator
812       then
813          First := Pat'First + 2;
814       end if;
815
816       Iterator.Regexp :=
817         GNAT.Regexp.Compile (Pat (First .. Pat'Last), Basic_Regexp, True);
818
819       Iterator.Maximum_Depth := 1;
820
821       --  Maximum_Depth is equal to 1 plus the number of directory separators
822       --  in the pattern.
823
824       for Index in First .. Pat'Last loop
825          if Pat (Index) = Directory_Separator then
826             Iterator.Maximum_Depth := Iterator.Maximum_Depth + 1;
827             exit when Iterator.Maximum_Depth = Max_Depth;
828          end if;
829       end loop;
830
831    end Start_Expansion;
832
833 begin
834    Section (CL.Argument_Count + 1) := 0;
835 end GNAT.Command_Line;