1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . C O M M A N D _ L I N E --
9 -- Copyright (C) 1999-2009, Free Software Foundation, Inc. --
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 3, 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. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada.Unchecked_Deallocation;
33 with Ada.Strings.Unbounded;
35 with GNAT.OS_Lib; use GNAT.OS_Lib;
37 package body GNAT.Command_Line is
39 package CL renames Ada.Command_Line;
41 type Switch_Parameter_Type is
43 Parameter_With_Optional_Space, -- ':' in getopt
44 Parameter_With_Space_Or_Equal, -- '=' in getopt
45 Parameter_No_Space, -- '!' in getopt
46 Parameter_Optional); -- '?' in getopt
48 procedure Set_Parameter
49 (Variable : out Parameter_Type;
53 Extra : Character := ASCII.NUL);
54 pragma Inline (Set_Parameter);
55 -- Set the parameter that will be returned by Parameter below
56 -- Parameters need to be defined ???
58 function Goto_Next_Argument_In_Section (Parser : Opt_Parser) return Boolean;
59 -- Go to the next argument on the command line. If we are at the end of
60 -- the current section, we want to make sure there is no other identical
61 -- section on the command line (there might be multiple instances of
62 -- -largs). Returns True iff there is another argument.
64 function Get_File_Names_Case_Sensitive return Integer;
65 pragma Import (C, Get_File_Names_Case_Sensitive,
66 "__gnat_get_file_names_case_sensitive");
68 File_Names_Case_Sensitive : constant Boolean :=
69 Get_File_Names_Case_Sensitive /= 0;
71 procedure Canonical_Case_File_Name (S : in out String);
72 -- Given a file name, converts it to canonical case form. For systems where
73 -- file names are case sensitive, this procedure has no effect. If file
74 -- names are not case sensitive (i.e. for example if you have the file
75 -- "xyz.adb", you can refer to it as XYZ.adb or XyZ.AdB), then this call
76 -- converts the given string to canonical all lower case form, so that two
77 -- file names compare equal if they refer to the same file.
79 procedure Internal_Initialize_Option_Scan
81 Switch_Char : Character;
82 Stop_At_First_Non_Switch : Boolean;
83 Section_Delimiters : String);
84 -- Initialize Parser, which must have been allocated already
86 function Argument (Parser : Opt_Parser; Index : Integer) return String;
87 -- Return the index-th command line argument
89 procedure Find_Longest_Matching_Switch
92 Index_In_Switches : out Integer;
93 Switch_Length : out Integer;
94 Param : out Switch_Parameter_Type);
95 -- Return the Longest switch from Switches that at least partially
96 -- partially Arg. Index_In_Switches is set to 0 if none matches.
97 -- What are other parameters??? in particular Param is not always set???
99 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
100 (Argument_List, Argument_List_Access);
102 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
103 (Command_Line_Configuration_Record, Command_Line_Configuration);
105 procedure Remove (Line : in out Argument_List_Access; Index : Integer);
106 -- Remove a specific element from Line
109 (Line : in out Argument_List_Access;
111 Before : Boolean := False);
112 -- Add a new element to Line. If Before is True, the item is inserted at
113 -- the beginning, else it is appended.
115 function Can_Have_Parameter (S : String) return Boolean;
116 -- True if S can have a parameter.
118 function Require_Parameter (S : String) return Boolean;
119 -- True if S requires a parameter.
121 function Actual_Switch (S : String) return String;
122 -- Remove any possible trailing '!', ':', '?' and '='
125 with procedure Callback (Simple_Switch : String; Parameter : String);
126 procedure For_Each_Simple_Switch
129 Parameter : String := "";
130 Unalias : Boolean := True);
131 -- Breaks Switch into as simple switches as possible (expanding aliases and
132 -- ungrouping common prefixes when possible), and call Callback for each of
135 procedure Sort_Sections
136 (Line : GNAT.OS_Lib.Argument_List_Access;
137 Sections : GNAT.OS_Lib.Argument_List_Access;
138 Params : GNAT.OS_Lib.Argument_List_Access);
139 -- Reorder the command line switches so that the switches belonging to a
140 -- section are grouped together.
142 procedure Group_Switches
144 Result : Argument_List_Access;
145 Sections : Argument_List_Access;
146 Params : Argument_List_Access);
147 -- Group switches with common prefixes whenever possible. Once they have
148 -- been grouped, we also check items for possible aliasing.
150 procedure Alias_Switches
152 Result : Argument_List_Access;
153 Params : Argument_List_Access);
154 -- When possible, replace one or more switches by an alias, i.e. a shorter
160 Substring : String) return Boolean;
161 -- Return True if the characters starting at Index in Type_Str are
162 -- equivalent to Substring.
168 function Argument (Parser : Opt_Parser; Index : Integer) return String is
170 if Parser.Arguments /= null then
171 return Parser.Arguments (Index + Parser.Arguments'First - 1).all;
173 return CL.Argument (Index);
177 ------------------------------
178 -- Canonical_Case_File_Name --
179 ------------------------------
181 procedure Canonical_Case_File_Name (S : in out String) is
183 if not File_Names_Case_Sensitive then
184 for J in S'Range loop
185 if S (J) in 'A' .. 'Z' then
186 S (J) := Character'Val
187 (Character'Pos (S (J)) +
188 Character'Pos ('a') -
189 Character'Pos ('A'));
193 end Canonical_Case_File_Name;
199 function Expansion (Iterator : Expansion_Iterator) return String is
200 use GNAT.Directory_Operations;
201 type Pointer is access all Expansion_Iterator;
203 It : constant Pointer := Iterator'Unrestricted_Access;
204 S : String (1 .. 1024);
207 Current : Depth := It.Current_Depth;
211 -- It is assumed that a directory is opened at the current level.
212 -- Otherwise GNAT.Directory_Operations.Directory_Error will be raised
213 -- at the first call to Read.
216 Read (It.Levels (Current).Dir, S, Last);
218 -- If we have exhausted the directory, close it and go back one level
221 Close (It.Levels (Current).Dir);
223 -- If we are at level 1, we are finished; return an empty string
226 return String'(1 .. 0 => ' ');
228 -- Otherwise continue with the directory at the previous level
230 Current := Current - 1;
231 It.Current_Depth := Current;
234 -- If this is a directory, that is neither "." or "..", attempt to
235 -- go to the next level.
238 (It.Dir_Name (1 .. It.Levels (Current).Name_Last) & S (1 .. Last))
239 and then S (1 .. Last) /= "."
240 and then S (1 .. Last) /= ".."
242 -- We can go to the next level only if we have not reached the
245 if Current < It.Maximum_Depth then
246 NL := It.Levels (Current).Name_Last;
248 -- And if relative path of this new directory is not too long
250 if NL + Last + 1 < Max_Path_Length then
251 Current := Current + 1;
252 It.Current_Depth := Current;
253 It.Dir_Name (NL + 1 .. NL + Last) := S (1 .. Last);
255 It.Dir_Name (NL) := Directory_Separator;
256 It.Levels (Current).Name_Last := NL;
257 Canonical_Case_File_Name (It.Dir_Name (1 .. NL));
259 -- Open the new directory, and read from it
261 GNAT.Directory_Operations.Open
262 (It.Levels (Current).Dir, It.Dir_Name (1 .. NL));
267 -- Check the relative path against the pattern
269 -- Note that we try to match also against directory names, since
270 -- clients of this function may expect to retrieve directories.
274 It.Dir_Name (It.Start .. It.Levels (Current).Name_Last)
278 Canonical_Case_File_Name (Name);
280 -- If it matches return the relative path
282 if GNAT.Regexp.Match (Name, Iterator.Regexp) then
294 (Parser : Opt_Parser := Command_Line_Parser) return String
297 if Parser.The_Switch.Extra = ASCII.NUL then
298 return Argument (Parser, Parser.The_Switch.Arg_Num)
299 (Parser.The_Switch.First .. Parser.The_Switch.Last);
301 return Parser.The_Switch.Extra
302 & Argument (Parser, Parser.The_Switch.Arg_Num)
303 (Parser.The_Switch.First .. Parser.The_Switch.Last);
311 function Get_Argument
312 (Do_Expansion : Boolean := False;
313 Parser : Opt_Parser := Command_Line_Parser) return String
316 if Parser.In_Expansion then
318 S : constant String := Expansion (Parser.Expansion_It);
320 if S'Length /= 0 then
323 Parser.In_Expansion := False;
328 if Parser.Current_Argument > Parser.Arg_Count then
330 -- If this is the first time this function is called
332 if Parser.Current_Index = 1 then
333 Parser.Current_Argument := 1;
334 while Parser.Current_Argument <= Parser.Arg_Count
335 and then Parser.Section (Parser.Current_Argument) /=
336 Parser.Current_Section
338 Parser.Current_Argument := Parser.Current_Argument + 1;
341 return String'(1 .. 0 => ' ');
344 elsif Parser.Section (Parser.Current_Argument) = 0 then
345 while Parser.Current_Argument <= Parser.Arg_Count
346 and then Parser.Section (Parser.Current_Argument) /=
347 Parser.Current_Section
349 Parser.Current_Argument := Parser.Current_Argument + 1;
353 Parser.Current_Index := Integer'Last;
355 while Parser.Current_Argument <= Parser.Arg_Count
356 and then Parser.Is_Switch (Parser.Current_Argument)
358 Parser.Current_Argument := Parser.Current_Argument + 1;
361 if Parser.Current_Argument > Parser.Arg_Count then
362 return String'(1 .. 0 => ' ');
363 elsif Parser.Section (Parser.Current_Argument) = 0 then
364 return Get_Argument (Do_Expansion);
367 Parser.Current_Argument := Parser.Current_Argument + 1;
369 -- Could it be a file name with wild cards to expand?
373 Arg : constant String :=
374 Argument (Parser, Parser.Current_Argument - 1);
379 while Index <= Arg'Last loop
381 or else Arg (Index) = '?'
382 or else Arg (Index) = '['
384 Parser.In_Expansion := True;
385 Start_Expansion (Parser.Expansion_It, Arg);
386 return Get_Argument (Do_Expansion);
394 return Argument (Parser, Parser.Current_Argument - 1);
397 ----------------------------------
398 -- Find_Longest_Matching_Switch --
399 ----------------------------------
401 procedure Find_Longest_Matching_Switch
404 Index_In_Switches : out Integer;
405 Switch_Length : out Integer;
406 Param : out Switch_Parameter_Type)
409 Length : Natural := 1;
410 P : Switch_Parameter_Type;
413 Index_In_Switches := 0;
416 -- Remove all leading spaces first to make sure that Index points
417 -- at the start of the first switch.
419 Index := Switches'First;
420 while Index <= Switches'Last and then Switches (Index) = ' ' loop
424 while Index <= Switches'Last loop
426 -- Search the length of the parameter at this position in Switches
429 while Length <= Switches'Last
430 and then Switches (Length) /= ' '
432 Length := Length + 1;
435 if Length = Index + 1 then
438 case Switches (Length - 1) is
440 P := Parameter_With_Optional_Space;
441 Length := Length - 1;
443 P := Parameter_With_Space_Or_Equal;
444 Length := Length - 1;
446 P := Parameter_No_Space;
447 Length := Length - 1;
449 P := Parameter_Optional;
450 Length := Length - 1;
456 -- If it is the one we searched, it may be a candidate
458 if Arg'First + Length - 1 - Index <= Arg'Last
459 and then Switches (Index .. Length - 1) =
460 Arg (Arg'First .. Arg'First + Length - 1 - Index)
461 and then Length - Index > Switch_Length
464 Index_In_Switches := Index;
465 Switch_Length := Length - Index;
468 -- Look for the next switch in Switches
470 while Index <= Switches'Last
471 and then Switches (Index) /= ' '
478 end Find_Longest_Matching_Switch;
486 Concatenate : Boolean := True;
487 Parser : Opt_Parser := Command_Line_Parser) return Character
490 pragma Unreferenced (Dummy);
495 -- If we have finished parsing the current command line item (there
496 -- might be multiple switches in a single item), then go to the next
499 if Parser.Current_Argument > Parser.Arg_Count
500 or else (Parser.Current_Index >
501 Argument (Parser, Parser.Current_Argument)'Last
502 and then not Goto_Next_Argument_In_Section (Parser))
507 -- By default, the switch will not have a parameter
509 Parser.The_Parameter :=
510 (Integer'Last, Integer'Last, Integer'Last - 1, ASCII.NUL);
511 Parser.The_Separator := ASCII.NUL;
514 Arg : constant String :=
515 Argument (Parser, Parser.Current_Argument);
516 Index_Switches : Natural := 0;
517 Max_Length : Natural := 0;
519 Param : Switch_Parameter_Type;
521 -- If we are on a new item, test if this might be a switch
523 if Parser.Current_Index = Arg'First then
524 if Arg (Arg'First) /= Parser.Switch_Character then
526 -- If it isn't a switch, return it immediately. We also know it
527 -- isn't the parameter to a previous switch, since that has
528 -- already been handled
530 if Switches (Switches'First) = '*' then
533 Arg_Num => Parser.Current_Argument,
536 Parser.Is_Switch (Parser.Current_Argument) := True;
537 Dummy := Goto_Next_Argument_In_Section (Parser);
541 if Parser.Stop_At_First then
542 Parser.Current_Argument := Positive'Last;
545 elsif not Goto_Next_Argument_In_Section (Parser) then
549 -- Recurse to get the next switch on the command line
555 -- We are on the first character of a new command line argument,
556 -- which starts with Switch_Character. Further analysis is needed.
558 Parser.Current_Index := Parser.Current_Index + 1;
559 Parser.Is_Switch (Parser.Current_Argument) := True;
562 Find_Longest_Matching_Switch
563 (Switches => Switches,
564 Arg => Arg (Parser.Current_Index .. Arg'Last),
565 Index_In_Switches => Index_Switches,
566 Switch_Length => Max_Length,
569 -- If switch is not accepted, it is either invalid or is returned
570 -- in the context of '*'.
572 if Index_Switches = 0 then
574 -- Depending on the value of Concatenate, the full switch is
575 -- a single character or the rest of the argument.
578 End_Index := Parser.Current_Index;
580 End_Index := Arg'Last;
583 if Switches (Switches'First) = '*' then
585 -- Always prepend the switch character, so that users know that
586 -- this comes from a switch on the command line. This is
587 -- especially important when Concatenate is False, since
588 -- otherwise the current argument first character is lost.
592 Arg_Num => Parser.Current_Argument,
593 First => Parser.Current_Index,
595 Extra => Parser.Switch_Character);
596 Parser.Is_Switch (Parser.Current_Argument) := True;
597 Dummy := Goto_Next_Argument_In_Section (Parser);
603 Arg_Num => Parser.Current_Argument,
604 First => Parser.Current_Index,
606 Parser.Current_Index := End_Index + 1;
607 raise Invalid_Switch;
610 End_Index := Parser.Current_Index + Max_Length - 1;
613 Arg_Num => Parser.Current_Argument,
614 First => Parser.Current_Index,
618 when Parameter_With_Optional_Space =>
619 if End_Index < Arg'Last then
621 (Parser.The_Parameter,
622 Arg_Num => Parser.Current_Argument,
623 First => End_Index + 1,
625 Dummy := Goto_Next_Argument_In_Section (Parser);
627 elsif Parser.Current_Argument < Parser.Arg_Count
628 and then Parser.Section (Parser.Current_Argument + 1) /= 0
630 Parser.Current_Argument := Parser.Current_Argument + 1;
631 Parser.The_Separator := ' ';
633 (Parser.The_Parameter,
634 Arg_Num => Parser.Current_Argument,
635 First => Argument (Parser, Parser.Current_Argument)'First,
636 Last => Argument (Parser, Parser.Current_Argument)'Last);
637 Parser.Is_Switch (Parser.Current_Argument) := True;
638 Dummy := Goto_Next_Argument_In_Section (Parser);
641 Parser.Current_Index := End_Index + 1;
642 raise Invalid_Parameter;
645 when Parameter_With_Space_Or_Equal =>
647 -- If the switch is of the form <switch>=xxx
649 if End_Index < Arg'Last then
651 if Arg (End_Index + 1) = '='
652 and then End_Index + 1 < Arg'Last
654 Parser.The_Separator := '=';
656 (Parser.The_Parameter,
657 Arg_Num => Parser.Current_Argument,
658 First => End_Index + 2,
660 Dummy := Goto_Next_Argument_In_Section (Parser);
662 Parser.Current_Index := End_Index + 1;
663 raise Invalid_Parameter;
666 -- If the switch is of the form <switch> xxx
668 elsif Parser.Current_Argument < Parser.Arg_Count
669 and then Parser.Section (Parser.Current_Argument + 1) /= 0
671 Parser.Current_Argument := Parser.Current_Argument + 1;
672 Parser.The_Separator := ' ';
674 (Parser.The_Parameter,
675 Arg_Num => Parser.Current_Argument,
676 First => Argument (Parser, Parser.Current_Argument)'First,
677 Last => Argument (Parser, Parser.Current_Argument)'Last);
678 Parser.Is_Switch (Parser.Current_Argument) := True;
679 Dummy := Goto_Next_Argument_In_Section (Parser);
682 Parser.Current_Index := End_Index + 1;
683 raise Invalid_Parameter;
686 when Parameter_No_Space =>
688 if End_Index < Arg'Last then
690 (Parser.The_Parameter,
691 Arg_Num => Parser.Current_Argument,
692 First => End_Index + 1,
694 Dummy := Goto_Next_Argument_In_Section (Parser);
697 Parser.Current_Index := End_Index + 1;
698 raise Invalid_Parameter;
701 when Parameter_Optional =>
703 if End_Index < Arg'Last then
705 (Parser.The_Parameter,
706 Arg_Num => Parser.Current_Argument,
707 First => End_Index + 1,
711 Dummy := Goto_Next_Argument_In_Section (Parser);
713 when Parameter_None =>
715 if Concatenate or else End_Index = Arg'Last then
716 Parser.Current_Index := End_Index + 1;
719 -- If Concatenate is False and the full argument is not
720 -- recognized as a switch, this is an invalid switch.
722 if Switches (Switches'First) = '*' then
725 Arg_Num => Parser.Current_Argument,
728 Parser.Is_Switch (Parser.Current_Argument) := True;
729 Dummy := Goto_Next_Argument_In_Section (Parser);
735 Arg_Num => Parser.Current_Argument,
736 First => Parser.Current_Index,
738 Parser.Current_Index := Arg'Last + 1;
739 raise Invalid_Switch;
743 return Switches (Index_Switches);
747 -----------------------------------
748 -- Goto_Next_Argument_In_Section --
749 -----------------------------------
751 function Goto_Next_Argument_In_Section
752 (Parser : Opt_Parser) return Boolean
755 Parser.Current_Argument := Parser.Current_Argument + 1;
757 if Parser.Current_Argument > Parser.Arg_Count
758 or else Parser.Section (Parser.Current_Argument) = 0
761 Parser.Current_Argument := Parser.Current_Argument + 1;
763 if Parser.Current_Argument > Parser.Arg_Count then
764 Parser.Current_Index := 1;
768 exit when Parser.Section (Parser.Current_Argument) =
769 Parser.Current_Section;
773 Parser.Current_Index :=
774 Argument (Parser, Parser.Current_Argument)'First;
777 end Goto_Next_Argument_In_Section;
783 procedure Goto_Section
784 (Name : String := "";
785 Parser : Opt_Parser := Command_Line_Parser)
790 Parser.In_Expansion := False;
793 Parser.Current_Argument := 1;
794 Parser.Current_Index := 1;
795 Parser.Current_Section := 1;
800 while Index <= Parser.Arg_Count loop
801 if Parser.Section (Index) = 0
802 and then Argument (Parser, Index) = Parser.Switch_Character & Name
804 Parser.Current_Argument := Index + 1;
805 Parser.Current_Index := 1;
807 if Parser.Current_Argument <= Parser.Arg_Count then
808 Parser.Current_Section :=
809 Parser.Section (Parser.Current_Argument);
817 Parser.Current_Argument := Positive'Last;
818 Parser.Current_Index := 2; -- so that Get_Argument returns nothing
821 ----------------------------
822 -- Initialize_Option_Scan --
823 ----------------------------
825 procedure Initialize_Option_Scan
826 (Switch_Char : Character := '-';
827 Stop_At_First_Non_Switch : Boolean := False;
828 Section_Delimiters : String := "")
831 Internal_Initialize_Option_Scan
832 (Parser => Command_Line_Parser,
833 Switch_Char => Switch_Char,
834 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
835 Section_Delimiters => Section_Delimiters);
836 end Initialize_Option_Scan;
838 ----------------------------
839 -- Initialize_Option_Scan --
840 ----------------------------
842 procedure Initialize_Option_Scan
843 (Parser : out Opt_Parser;
844 Command_Line : GNAT.OS_Lib.Argument_List_Access;
845 Switch_Char : Character := '-';
846 Stop_At_First_Non_Switch : Boolean := False;
847 Section_Delimiters : String := "")
852 if Command_Line = null then
853 Parser := new Opt_Parser_Data (CL.Argument_Count);
854 Initialize_Option_Scan
855 (Switch_Char => Switch_Char,
856 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
857 Section_Delimiters => Section_Delimiters);
859 Parser := new Opt_Parser_Data (Command_Line'Length);
860 Parser.Arguments := Command_Line;
861 Internal_Initialize_Option_Scan
863 Switch_Char => Switch_Char,
864 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
865 Section_Delimiters => Section_Delimiters);
867 end Initialize_Option_Scan;
869 -------------------------------------
870 -- Internal_Initialize_Option_Scan --
871 -------------------------------------
873 procedure Internal_Initialize_Option_Scan
874 (Parser : Opt_Parser;
875 Switch_Char : Character;
876 Stop_At_First_Non_Switch : Boolean;
877 Section_Delimiters : String)
879 Section_Num : Section_Number;
880 Section_Index : Integer;
882 Delimiter_Found : Boolean;
885 pragma Warnings (Off, Discard);
888 Parser.Current_Argument := 0;
889 Parser.Current_Index := 0;
890 Parser.In_Expansion := False;
891 Parser.Switch_Character := Switch_Char;
892 Parser.Stop_At_First := Stop_At_First_Non_Switch;
894 -- If we are using sections, we have to preprocess the command line
895 -- to delimit them. A section can be repeated, so we just give each
896 -- item on the command line a section number
899 Section_Index := Section_Delimiters'First;
900 while Section_Index <= Section_Delimiters'Last loop
901 Last := Section_Index;
902 while Last <= Section_Delimiters'Last
903 and then Section_Delimiters (Last) /= ' '
908 Delimiter_Found := False;
909 Section_Num := Section_Num + 1;
911 for Index in 1 .. Parser.Arg_Count loop
912 if Argument (Parser, Index)(1) = Parser.Switch_Character
914 Argument (Parser, Index) = Parser.Switch_Character &
916 (Section_Index .. Last - 1)
918 Parser.Section (Index) := 0;
919 Delimiter_Found := True;
921 elsif Parser.Section (Index) = 0 then
922 Delimiter_Found := False;
924 elsif Delimiter_Found then
925 Parser.Section (Index) := Section_Num;
929 Section_Index := Last + 1;
930 while Section_Index <= Section_Delimiters'Last
931 and then Section_Delimiters (Section_Index) = ' '
933 Section_Index := Section_Index + 1;
937 Discard := Goto_Next_Argument_In_Section (Parser);
938 end Internal_Initialize_Option_Scan;
945 (Parser : Opt_Parser := Command_Line_Parser) return String
948 if Parser.The_Parameter.First > Parser.The_Parameter.Last then
949 return String'(1 .. 0 => ' ');
951 return Argument (Parser, Parser.The_Parameter.Arg_Num)
952 (Parser.The_Parameter.First .. Parser.The_Parameter.Last);
961 (Parser : Opt_Parser := Command_Line_Parser) return Character
964 return Parser.The_Separator;
971 procedure Set_Parameter
972 (Variable : out Parameter_Type;
976 Extra : Character := ASCII.NUL)
979 Variable.Arg_Num := Arg_Num;
980 Variable.First := First;
981 Variable.Last := Last;
982 Variable.Extra := Extra;
985 ---------------------
986 -- Start_Expansion --
987 ---------------------
989 procedure Start_Expansion
990 (Iterator : out Expansion_Iterator;
992 Directory : String := "";
993 Basic_Regexp : Boolean := True)
995 Directory_Separator : Character;
996 pragma Import (C, Directory_Separator, "__gnat_dir_separator");
998 First : Positive := Pattern'First;
999 Pat : String := Pattern;
1002 Canonical_Case_File_Name (Pat);
1003 Iterator.Current_Depth := 1;
1005 -- If Directory is unspecified, use the current directory ("./" or ".\")
1007 if Directory = "" then
1008 Iterator.Dir_Name (1 .. 2) := "." & Directory_Separator;
1009 Iterator.Start := 3;
1012 Iterator.Dir_Name (1 .. Directory'Length) := Directory;
1013 Iterator.Start := Directory'Length + 1;
1014 Canonical_Case_File_Name (Iterator.Dir_Name (1 .. Directory'Length));
1016 -- Make sure that the last character is a directory separator
1018 if Directory (Directory'Last) /= Directory_Separator then
1019 Iterator.Dir_Name (Iterator.Start) := Directory_Separator;
1020 Iterator.Start := Iterator.Start + 1;
1024 Iterator.Levels (1).Name_Last := Iterator.Start - 1;
1026 -- Open the initial Directory, at depth 1
1028 GNAT.Directory_Operations.Open
1029 (Iterator.Levels (1).Dir, Iterator.Dir_Name (1 .. Iterator.Start - 1));
1031 -- If in the current directory and the pattern starts with "./" or ".\",
1032 -- drop the "./" or ".\" from the pattern.
1034 if Directory = "" and then Pat'Length > 2
1035 and then Pat (Pat'First) = '.'
1036 and then Pat (Pat'First + 1) = Directory_Separator
1038 First := Pat'First + 2;
1042 GNAT.Regexp.Compile (Pat (First .. Pat'Last), Basic_Regexp, True);
1044 Iterator.Maximum_Depth := 1;
1046 -- Maximum_Depth is equal to 1 plus the number of directory separators
1049 for Index in First .. Pat'Last loop
1050 if Pat (Index) = Directory_Separator then
1051 Iterator.Maximum_Depth := Iterator.Maximum_Depth + 1;
1052 exit when Iterator.Maximum_Depth = Max_Depth;
1055 end Start_Expansion;
1061 procedure Free (Parser : in out Opt_Parser) is
1062 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1063 (Opt_Parser_Data, Opt_Parser);
1066 and then Parser /= Command_Line_Parser
1068 Free (Parser.Arguments);
1069 Unchecked_Free (Parser);
1077 procedure Define_Alias
1078 (Config : in out Command_Line_Configuration;
1083 if Config = null then
1084 Config := new Command_Line_Configuration_Record;
1087 Add (Config.Aliases, new String'(Switch));
1088 Add (Config.Expansions, new String'(Expanded));
1095 procedure Define_Prefix
1096 (Config : in out Command_Line_Configuration;
1100 if Config = null then
1101 Config := new Command_Line_Configuration_Record;
1104 Add (Config.Prefixes, new String'(Prefix));
1111 procedure Define_Switch
1112 (Config : in out Command_Line_Configuration;
1116 if Config = null then
1117 Config := new Command_Line_Configuration_Record;
1120 Add (Config.Switches, new String'(Switch));
1123 --------------------
1124 -- Define_Section --
1125 --------------------
1127 procedure Define_Section
1128 (Config : in out Command_Line_Configuration;
1132 if Config = null then
1133 Config := new Command_Line_Configuration_Record;
1136 Add (Config.Sections, new String'(Section));
1143 function Get_Switches
1144 (Config : Command_Line_Configuration;
1145 Switch_Char : Character)
1148 Ret : Ada.Strings.Unbounded.Unbounded_String;
1149 use type Ada.Strings.Unbounded.Unbounded_String;
1152 if Config = null or else Config.Switches = null then
1156 for J in Config.Switches'Range loop
1157 if Config.Switches (J) (Config.Switches (J)'First) = Switch_Char then
1161 (Config.Switches (J)'First + 1 .. Config.Switches (J)'Last);
1163 Ret := Ret & " " & Config.Switches (J).all;
1167 return Ada.Strings.Unbounded.To_String (Ret);
1170 -----------------------
1171 -- Set_Configuration --
1172 -----------------------
1174 procedure Set_Configuration
1175 (Cmd : in out Command_Line;
1176 Config : Command_Line_Configuration)
1179 Cmd.Config := Config;
1180 end Set_Configuration;
1182 -----------------------
1183 -- Get_Configuration --
1184 -----------------------
1186 function Get_Configuration
1187 (Cmd : Command_Line) return Command_Line_Configuration is
1190 end Get_Configuration;
1192 ----------------------
1193 -- Set_Command_Line --
1194 ----------------------
1196 procedure Set_Command_Line
1197 (Cmd : in out Command_Line;
1199 Getopt_Description : String := "";
1200 Switch_Char : Character := '-')
1202 Tmp : Argument_List_Access;
1203 Parser : Opt_Parser;
1205 Section : String_Access := null;
1207 function Real_Full_Switch
1209 Parser : Opt_Parser) return String;
1210 -- Ensure that the returned switch value contains the
1211 -- Switch_Char prefix if needed.
1213 ----------------------
1214 -- Real_Full_Switch --
1215 ----------------------
1217 function Real_Full_Switch
1219 Parser : Opt_Parser) return String
1223 return Full_Switch (Parser);
1225 return Switch_Char & Full_Switch (Parser);
1227 end Real_Full_Switch;
1229 -- Start of processing for Set_Command_Line
1232 Free (Cmd.Expanded);
1235 if Switches /= "" then
1236 Tmp := Argument_String_To_List (Switches);
1237 Initialize_Option_Scan (Parser, Tmp, Switch_Char);
1241 S := Getopt (Switches => "* " & Getopt_Description,
1242 Concatenate => False,
1244 exit when S = ASCII.NUL;
1247 Sw : constant String :=
1248 Real_Full_Switch (S, Parser);
1249 Is_Section : Boolean := False;
1252 if Cmd.Config /= null
1253 and then Cmd.Config.Sections /= null
1256 for S in Cmd.Config.Sections'Range loop
1257 if Sw = Cmd.Config.Sections (S).all then
1258 Section := Cmd.Config.Sections (S);
1261 exit Section_Search;
1263 end loop Section_Search;
1266 if not Is_Section then
1267 if Section = null then
1269 -- Work around some weird cases: some switches may
1270 -- expect parameters, but have the same value as
1271 -- longer switches: -gnaty3 (-gnaty, parameter=3) and
1272 -- -gnatya (-gnatya, no parameter).
1274 -- So we are calling add_switch here with parameter
1275 -- attached. This will be anyway correctly handled by
1276 -- Add_Switch if -gnaty3 is actually provided.
1278 if Separator (Parser) = ASCII.NUL then
1280 (Cmd, Sw & Parameter (Parser), "");
1283 (Cmd, Sw, Parameter (Parser), Separator (Parser));
1286 if Separator (Parser) = ASCII.NUL then
1288 (Cmd, Sw & Parameter (Parser), "",
1303 when Invalid_Parameter =>
1305 -- Add it with no parameter, if that's the way the user
1308 -- Specify the separator in all cases, as the switch might
1309 -- need to be unaliased, and the alias might contain
1310 -- switches with parameters.
1312 if Section = null then
1314 (Cmd, Switch_Char & Full_Switch (Parser),
1315 Separator => Separator (Parser));
1318 (Cmd, Switch_Char & Full_Switch (Parser),
1319 Separator => Separator (Parser),
1320 Section => Section.all);
1327 end Set_Command_Line;
1336 Substring : String) return Boolean is
1338 return Index + Substring'Length - 1 <= Type_Str'Last
1339 and then Type_Str (Index .. Index + Substring'Length - 1) = Substring;
1342 ------------------------
1343 -- Can_Have_Parameter --
1344 ------------------------
1346 function Can_Have_Parameter (S : String) return Boolean is
1348 if S'Length <= 1 then
1353 when '!' | ':' | '?' | '=' =>
1358 end Can_Have_Parameter;
1360 -----------------------
1361 -- Require_Parameter --
1362 -----------------------
1364 function Require_Parameter (S : String) return Boolean is
1366 if S'Length <= 1 then
1371 when '!' | ':' | '=' =>
1376 end Require_Parameter;
1382 function Actual_Switch (S : String) return String is
1384 if S'Length <= 1 then
1389 when '!' | ':' | '?' | '=' =>
1390 return S (S'First .. S'Last - 1);
1396 ----------------------------
1397 -- For_Each_Simple_Switch --
1398 ----------------------------
1400 procedure For_Each_Simple_Switch
1401 (Cmd : Command_Line;
1403 Parameter : String := "";
1404 Unalias : Boolean := True)
1406 function Group_Analysis
1408 Group : String) return Boolean;
1409 -- Perform the analysis of a group of switches
1411 --------------------
1412 -- Group_Analysis --
1413 --------------------
1415 function Group_Analysis
1417 Group : String) return Boolean
1424 while Idx <= Group'Last loop
1427 for S in Cmd.Config.Switches'Range loop
1429 Sw : constant String :=
1431 (Cmd.Config.Switches (S).all);
1432 Full : constant String :=
1433 Prefix & Group (Idx .. Group'Last);
1438 if Sw'Length >= Prefix'Length
1440 -- Verify that sw starts with Prefix
1442 and then Looking_At (Sw, Sw'First, Prefix)
1444 -- Verify that the group starts with sw
1446 and then Looking_At (Full, Full'First, Sw)
1448 Last := Idx + Sw'Length - Prefix'Length - 1;
1451 if Can_Have_Parameter (Cmd.Config.Switches (S).all) then
1453 -- Include potential parameter to the recursive call.
1454 -- Only numbers are allowed.
1456 while Last < Group'Last
1457 and then Group (Last + 1) in '0' .. '9'
1463 if not Require_Parameter (Cmd.Config.Switches (S).all)
1464 or else Last >= Param
1466 if Idx = Group'First
1467 and then Last = Group'Last
1468 and then Last < Param
1470 -- The group only concerns a single switch. Do not
1471 -- perform recursive call.
1473 -- Note that we still perform a recursive call if
1474 -- a parameter is detected in the switch, as this
1475 -- is a way to correctly identify such a parameter
1483 -- Recursive call, using the detected parameter if any
1485 if Last >= Param then
1486 For_Each_Simple_Switch
1488 Prefix & Group (Idx .. Param - 1),
1489 Group (Param .. Last));
1491 For_Each_Simple_Switch
1492 (Cmd, Prefix & Group (Idx .. Last), "");
1503 For_Each_Simple_Switch (Cmd, Prefix & Group (Idx), "");
1512 -- First determine if the switch corresponds to one belonging to the
1513 -- configuration. If so, run callback and exit.
1515 if Cmd.Config /= null and then Cmd.Config.Switches /= null then
1516 for S in Cmd.Config.Switches'Range loop
1518 Config_Switch : String renames Cmd.Config.Switches (S).all;
1520 if Actual_Switch (Config_Switch) = Switch
1522 ((Can_Have_Parameter (Config_Switch)
1523 and then Parameter /= "")
1525 (not Require_Parameter (Config_Switch)
1526 and then Parameter = ""))
1528 Callback (Switch, Parameter);
1535 -- If adding a switch that can in fact be expanded through aliases,
1536 -- add separately each of its expansions.
1538 -- This takes care of expansions like "-T" -> "-gnatwrs", where the
1539 -- alias and its expansion do not have the same prefix. Given the order
1540 -- in which we do things here, the expansion of the alias will itself
1541 -- be checked for a common prefix and split into simple switches.
1544 and then Cmd.Config /= null
1545 and then Cmd.Config.Aliases /= null
1547 for A in Cmd.Config.Aliases'Range loop
1548 if Cmd.Config.Aliases (A).all = Switch and then Parameter = "" then
1549 For_Each_Simple_Switch
1550 (Cmd, Cmd.Config.Expansions (A).all, "");
1556 -- If adding a switch grouping several switches, add each of the simple
1557 -- switches instead.
1559 if Cmd.Config /= null and then Cmd.Config.Prefixes /= null then
1560 for P in Cmd.Config.Prefixes'Range loop
1561 if Switch'Length > Cmd.Config.Prefixes (P)'Length + 1
1563 (Switch, Switch'First, Cmd.Config.Prefixes (P).all)
1565 -- Alias expansion will be done recursively
1567 if Cmd.Config.Switches = null then
1568 for S in Switch'First + Cmd.Config.Prefixes (P)'Length
1571 For_Each_Simple_Switch
1572 (Cmd, Cmd.Config.Prefixes (P).all & Switch (S), "");
1577 elsif Group_Analysis
1578 (Cmd.Config.Prefixes (P).all,
1580 (Switch'First + Cmd.Config.Prefixes (P)'Length
1583 -- Recursive calls already done on each switch of the group:
1584 -- Return without executing Callback.
1592 -- Test if added switch is a known switch with parameter attached
1595 and then Cmd.Config /= null
1596 and then Cmd.Config.Switches /= null
1598 for S in Cmd.Config.Switches'Range loop
1600 Sw : constant String :=
1601 Actual_Switch (Cmd.Config.Switches (S).all);
1606 -- Verify that switch starts with Sw
1607 -- What if the "verification" fails???
1609 if Switch'Length >= Sw'Length
1610 and then Looking_At (Switch, Switch'First, Sw)
1612 Param := Switch'First + Sw'Length - 1;
1615 if Can_Have_Parameter (Cmd.Config.Switches (S).all) then
1616 while Last < Switch'Last
1617 and then Switch (Last + 1) in '0' .. '9'
1623 -- If full Switch is a known switch with attached parameter
1624 -- then we use this parameter in the callback.
1626 if Last = Switch'Last then
1628 (Switch (Switch'First .. Param),
1629 Switch (Param + 1 .. Last));
1638 Callback (Switch, Parameter);
1639 end For_Each_Simple_Switch;
1645 procedure Add_Switch
1646 (Cmd : in out Command_Line;
1648 Parameter : String := "";
1649 Separator : Character := ' ';
1650 Section : String := "";
1651 Add_Before : Boolean := False)
1654 pragma Unreferenced (Success);
1657 (Cmd, Switch, Parameter, Separator, Section, Add_Before, Success);
1664 procedure Add_Switch
1665 (Cmd : in out Command_Line;
1667 Parameter : String := "";
1668 Separator : Character := ' ';
1669 Section : String := "";
1670 Add_Before : Boolean := False;
1671 Success : out Boolean)
1673 procedure Add_Simple_Switch (Simple : String; Param : String);
1674 -- Add a new switch that has had all its aliases expanded, and switches
1675 -- ungrouped. We know there are no more aliases in Switches.
1677 -----------------------
1678 -- Add_Simple_Switch --
1679 -----------------------
1681 procedure Add_Simple_Switch (Simple : String; Param : String) is
1683 if Cmd.Expanded = null then
1684 Cmd.Expanded := new Argument_List'(1 .. 1 => new String'(Simple));
1687 Cmd.Params := new Argument_List'
1688 (1 .. 1 => new String'(Separator & Param));
1691 Cmd.Params := new Argument_List'(1 .. 1 => null);
1694 if Section = "" then
1695 Cmd.Sections := new Argument_List'(1 .. 1 => null);
1698 Cmd.Sections := new Argument_List'
1699 (1 .. 1 => new String'(Section));
1703 -- Do we already have this switch?
1705 for C in Cmd.Expanded'Range loop
1706 if Cmd.Expanded (C).all = Simple
1708 ((Cmd.Params (C) = null and then Param = "")
1710 (Cmd.Params (C) /= null
1711 and then Cmd.Params (C).all = Separator & Param))
1713 ((Cmd.Sections (C) = null and then Section = "")
1715 (Cmd.Sections (C) /= null
1716 and then Cmd.Sections (C).all = Section))
1722 -- Inserting at least one switch
1725 Add (Cmd.Expanded, new String'(Simple), Add_Before);
1730 new String'(Separator & Param),
1740 if Section = "" then
1748 new String'(Section),
1752 end Add_Simple_Switch;
1754 procedure Add_Simple_Switches is
1755 new For_Each_Simple_Switch (Add_Simple_Switch);
1757 -- Start of processing for Add_Switch
1761 Add_Simple_Switches (Cmd, Switch, Parameter);
1762 Free (Cmd.Coalesce);
1769 procedure Remove (Line : in out Argument_List_Access; Index : Integer) is
1770 Tmp : Argument_List_Access := Line;
1773 Line := new Argument_List (Tmp'First .. Tmp'Last - 1);
1775 if Index /= Tmp'First then
1776 Line (Tmp'First .. Index - 1) := Tmp (Tmp'First .. Index - 1);
1781 if Index /= Tmp'Last then
1782 Line (Index .. Tmp'Last - 1) := Tmp (Index + 1 .. Tmp'Last);
1785 Unchecked_Free (Tmp);
1793 (Line : in out Argument_List_Access;
1794 Str : String_Access;
1795 Before : Boolean := False)
1797 Tmp : Argument_List_Access := Line;
1801 Line := new Argument_List (Tmp'First .. Tmp'Last + 1);
1804 Line (Tmp'First) := Str;
1805 Line (Tmp'First + 1 .. Tmp'Last + 1) := Tmp.all;
1807 Line (Tmp'Range) := Tmp.all;
1808 Line (Tmp'Last + 1) := Str;
1811 Unchecked_Free (Tmp);
1814 Line := new Argument_List'(1 .. 1 => Str);
1822 procedure Remove_Switch
1823 (Cmd : in out Command_Line;
1825 Remove_All : Boolean := False;
1826 Has_Parameter : Boolean := False;
1827 Section : String := "")
1830 pragma Unreferenced (Success);
1832 Remove_Switch (Cmd, Switch, Remove_All, Has_Parameter, Section, Success);
1839 procedure Remove_Switch
1840 (Cmd : in out Command_Line;
1842 Remove_All : Boolean := False;
1843 Has_Parameter : Boolean := False;
1844 Section : String := "";
1845 Success : out Boolean)
1847 procedure Remove_Simple_Switch (Simple : String; Param : String);
1848 -- Removes a simple switch, with no aliasing or grouping
1850 --------------------------
1851 -- Remove_Simple_Switch --
1852 --------------------------
1854 procedure Remove_Simple_Switch (Simple : String; Param : String) is
1856 pragma Unreferenced (Param);
1859 if Cmd.Expanded /= null then
1860 C := Cmd.Expanded'First;
1861 while C <= Cmd.Expanded'Last loop
1862 if Cmd.Expanded (C).all = Simple
1865 or else (Cmd.Sections (C) = null
1866 and then Section = "")
1867 or else (Cmd.Sections (C) /= null
1868 and then Section = Cmd.Sections (C).all))
1869 and then (not Has_Parameter or else Cmd.Params (C) /= null)
1871 Remove (Cmd.Expanded, C);
1872 Remove (Cmd.Params, C);
1873 Remove (Cmd.Sections, C);
1876 if not Remove_All then
1885 end Remove_Simple_Switch;
1887 procedure Remove_Simple_Switches is
1888 new For_Each_Simple_Switch (Remove_Simple_Switch);
1890 -- Start of processing for Remove_Switch
1894 Remove_Simple_Switches (Cmd, Switch, "", Unalias => not Has_Parameter);
1895 Free (Cmd.Coalesce);
1902 procedure Remove_Switch
1903 (Cmd : in out Command_Line;
1906 Section : String := "")
1908 procedure Remove_Simple_Switch (Simple : String; Param : String);
1909 -- Removes a simple switch, with no aliasing or grouping
1911 --------------------------
1912 -- Remove_Simple_Switch --
1913 --------------------------
1915 procedure Remove_Simple_Switch (Simple : String; Param : String) is
1919 if Cmd.Expanded /= null then
1920 C := Cmd.Expanded'First;
1921 while C <= Cmd.Expanded'Last loop
1922 if Cmd.Expanded (C).all = Simple
1924 ((Cmd.Sections (C) = null
1925 and then Section = "")
1927 (Cmd.Sections (C) /= null
1928 and then Section = Cmd.Sections (C).all))
1930 ((Cmd.Params (C) = null and then Param = "")
1932 (Cmd.Params (C) /= null
1935 -- Ignore the separator stored in Parameter
1937 Cmd.Params (C) (Cmd.Params (C)'First + 1
1938 .. Cmd.Params (C)'Last) =
1941 Remove (Cmd.Expanded, C);
1942 Remove (Cmd.Params, C);
1943 Remove (Cmd.Sections, C);
1945 -- The switch is necessarily unique by construction of
1955 end Remove_Simple_Switch;
1957 procedure Remove_Simple_Switches is
1958 new For_Each_Simple_Switch (Remove_Simple_Switch);
1960 -- Start of processing for Remove_Switch
1963 Remove_Simple_Switches (Cmd, Switch, Parameter);
1964 Free (Cmd.Coalesce);
1967 --------------------
1968 -- Group_Switches --
1969 --------------------
1971 procedure Group_Switches
1972 (Cmd : Command_Line;
1973 Result : Argument_List_Access;
1974 Sections : Argument_List_Access;
1975 Params : Argument_List_Access)
1977 function Compatible_Parameter (Param : String_Access) return Boolean;
1978 -- True when the parameter can be part of a group
1980 --------------------------
1981 -- Compatible_Parameter --
1982 --------------------------
1984 function Compatible_Parameter (Param : String_Access) return Boolean is
1988 if Param = null then
1991 -- We need parameters without separators
1993 elsif Param (Param'First) /= ASCII.NUL then
1996 -- Parameters must be all digits
1999 for J in Param'First + 1 .. Param'Last loop
2000 if Param (J) not in '0' .. '9' then
2007 end Compatible_Parameter;
2009 -- Local declarations
2011 Group : Ada.Strings.Unbounded.Unbounded_String;
2013 use type Ada.Strings.Unbounded.Unbounded_String;
2015 -- Start of processing for Group_Switches
2018 if Cmd.Config = null
2019 or else Cmd.Config.Prefixes = null
2024 for P in Cmd.Config.Prefixes'Range loop
2025 Group := Ada.Strings.Unbounded.Null_Unbounded_String;
2028 for C in Result'Range loop
2029 if Result (C) /= null
2030 and then Compatible_Parameter (Params (C))
2032 (Result (C).all, Result (C)'First, Cmd.Config.Prefixes (P).all)
2034 -- If we are still in the same section, group the switches
2038 (Sections (C) = null
2039 and then Sections (First) = null)
2041 (Sections (C) /= null
2042 and then Sections (First) /= null
2043 and then Sections (C).all = Sections (First).all)
2048 (Result (C)'First + Cmd.Config.Prefixes (P)'Length ..
2051 if Params (C) /= null then
2054 Params (C) (Params (C)'First + 1 .. Params (C)'Last);
2065 -- We changed section: we put the grouped switches to the
2066 -- first place, on continue with the new section.
2070 (Cmd.Config.Prefixes (P).all &
2071 Ada.Strings.Unbounded.To_String (Group));
2073 Ada.Strings.Unbounded.To_Unbounded_String
2075 (Result (C)'First + Cmd.Config.Prefixes (P)'Length ..
2085 (Cmd.Config.Prefixes (P).all &
2086 Ada.Strings.Unbounded.To_String (Group));
2091 --------------------
2092 -- Alias_Switches --
2093 --------------------
2095 procedure Alias_Switches
2096 (Cmd : Command_Line;
2097 Result : Argument_List_Access;
2098 Params : Argument_List_Access)
2103 procedure Check_Cb (Switch : String; Param : String);
2104 -- Comment required ???
2106 procedure Remove_Cb (Switch : String; Param : String);
2107 -- Comment required ???
2113 procedure Check_Cb (Switch : String; Param : String) is
2116 for E in Result'Range loop
2117 if Result (E) /= null
2120 or else Params (E) (Params (E)'First + 1
2121 .. Params (E)'Last) = Param)
2122 and then Result (E).all = Switch
2136 procedure Remove_Cb (Switch : String; Param : String) is
2138 for E in Result'Range loop
2139 if Result (E) /= null
2142 or else Params (E) (Params (E)'First + 1
2143 .. Params (E)'Last) = Param)
2144 and then Result (E).all = Switch
2156 procedure Check_All is new For_Each_Simple_Switch (Check_Cb);
2157 procedure Remove_All is new For_Each_Simple_Switch (Remove_Cb);
2159 -- Start of processing for Alias_Switches
2162 if Cmd.Config = null
2163 or else Cmd.Config.Aliases = null
2168 for A in Cmd.Config.Aliases'Range loop
2170 -- Compute the various simple switches that make up the alias. We
2171 -- split the expansion into as many simple switches as possible, and
2172 -- then check whether the expanded command line has all of them.
2175 Check_All (Cmd, Cmd.Config.Expansions (A).all);
2178 First := Integer'Last;
2179 Remove_All (Cmd, Cmd.Config.Expansions (A).all);
2180 Result (First) := new String'(Cmd.Config.Aliases (A).all);
2189 procedure Sort_Sections
2190 (Line : GNAT.OS_Lib.Argument_List_Access;
2191 Sections : GNAT.OS_Lib.Argument_List_Access;
2192 Params : GNAT.OS_Lib.Argument_List_Access)
2194 Sections_List : Argument_List_Access :=
2195 new Argument_List'(1 .. 1 => null);
2197 Old_Line : constant Argument_List := Line.all;
2198 Old_Sections : constant Argument_List := Sections.all;
2199 Old_Params : constant Argument_List := Params.all;
2207 -- First construct a list of all sections
2209 for E in Line'Range loop
2210 if Sections (E) /= null then
2212 for S in Sections_List'Range loop
2213 if (Sections_List (S) = null and then Sections (E) = null)
2215 (Sections_List (S) /= null
2216 and then Sections (E) /= null
2217 and then Sections_List (S).all = Sections (E).all)
2225 Add (Sections_List, Sections (E));
2230 Index := Line'First;
2232 for S in Sections_List'Range loop
2233 for E in Old_Line'Range loop
2234 if (Sections_List (S) = null and then Old_Sections (E) = null)
2236 (Sections_List (S) /= null
2237 and then Old_Sections (E) /= null
2238 and then Sections_List (S).all = Old_Sections (E).all)
2240 Line (Index) := Old_Line (E);
2241 Sections (Index) := Old_Sections (E);
2242 Params (Index) := Old_Params (E);
2254 (Cmd : in out Command_Line;
2255 Iter : in out Command_Line_Iterator;
2259 if Cmd.Expanded = null then
2264 -- Reorder the expanded line so that sections are grouped
2266 Sort_Sections (Cmd.Expanded, Cmd.Sections, Cmd.Params);
2268 -- Coalesce the switches as much as possible
2271 and then Cmd.Coalesce = null
2273 Cmd.Coalesce := new Argument_List (Cmd.Expanded'Range);
2274 for E in Cmd.Expanded'Range loop
2275 Cmd.Coalesce (E) := new String'(Cmd.Expanded (E).all);
2278 Cmd.Coalesce_Sections := new Argument_List (Cmd.Sections'Range);
2279 for E in Cmd.Sections'Range loop
2280 if Cmd.Sections (E) = null then
2281 Cmd.Coalesce_Sections (E) := null;
2283 Cmd.Coalesce_Sections (E) := new String'(Cmd.Sections (E).all);
2287 Cmd.Coalesce_Params := new Argument_List (Cmd.Params'Range);
2288 for E in Cmd.Params'Range loop
2289 if Cmd.Params (E) = null then
2290 Cmd.Coalesce_Params (E) := null;
2292 Cmd.Coalesce_Params (E) := new String'(Cmd.Params (E).all);
2296 -- Not a clone, since we will not modify the parameters anyway
2298 Alias_Switches (Cmd, Cmd.Coalesce, Cmd.Coalesce_Params);
2300 (Cmd, Cmd.Coalesce, Cmd.Coalesce_Sections, Cmd.Coalesce_Params);
2304 Iter.List := Cmd.Expanded;
2305 Iter.Params := Cmd.Params;
2306 Iter.Sections := Cmd.Sections;
2308 Iter.List := Cmd.Coalesce;
2309 Iter.Params := Cmd.Coalesce_Params;
2310 Iter.Sections := Cmd.Coalesce_Sections;
2313 if Iter.List = null then
2314 Iter.Current := Integer'Last;
2316 Iter.Current := Iter.List'First;
2318 while Iter.Current <= Iter.List'Last
2319 and then Iter.List (Iter.Current) = null
2321 Iter.Current := Iter.Current + 1;
2326 --------------------
2327 -- Current_Switch --
2328 --------------------
2330 function Current_Switch (Iter : Command_Line_Iterator) return String is
2332 return Iter.List (Iter.Current).all;
2335 --------------------
2336 -- Is_New_Section --
2337 --------------------
2339 function Is_New_Section (Iter : Command_Line_Iterator) return Boolean is
2340 Section : constant String := Current_Section (Iter);
2342 if Iter.Sections = null then
2344 elsif Iter.Current = Iter.Sections'First
2345 or else Iter.Sections (Iter.Current - 1) = null
2347 return Section /= "";
2350 return Section /= Iter.Sections (Iter.Current - 1).all;
2353 ---------------------
2354 -- Current_Section --
2355 ---------------------
2357 function Current_Section (Iter : Command_Line_Iterator) return String is
2359 if Iter.Sections = null
2360 or else Iter.Current > Iter.Sections'Last
2361 or else Iter.Sections (Iter.Current) = null
2366 return Iter.Sections (Iter.Current).all;
2367 end Current_Section;
2369 -----------------------
2370 -- Current_Separator --
2371 -----------------------
2373 function Current_Separator (Iter : Command_Line_Iterator) return String is
2375 if Iter.Params = null
2376 or else Iter.Current > Iter.Params'Last
2377 or else Iter.Params (Iter.Current) = null
2383 Sep : constant Character :=
2384 Iter.Params (Iter.Current) (Iter.Params (Iter.Current)'First);
2386 if Sep = ASCII.NUL then
2393 end Current_Separator;
2395 -----------------------
2396 -- Current_Parameter --
2397 -----------------------
2399 function Current_Parameter (Iter : Command_Line_Iterator) return String is
2401 if Iter.Params = null
2402 or else Iter.Current > Iter.Params'Last
2403 or else Iter.Params (Iter.Current) = null
2409 P : constant String := Iter.Params (Iter.Current).all;
2414 return P (P'First + 1 .. P'Last);
2417 end Current_Parameter;
2423 function Has_More (Iter : Command_Line_Iterator) return Boolean is
2425 return Iter.List /= null and then Iter.Current <= Iter.List'Last;
2432 procedure Next (Iter : in out Command_Line_Iterator) is
2434 Iter.Current := Iter.Current + 1;
2435 while Iter.Current <= Iter.List'Last
2436 and then Iter.List (Iter.Current) = null
2438 Iter.Current := Iter.Current + 1;
2446 procedure Free (Config : in out Command_Line_Configuration) is
2448 if Config /= null then
2449 Free (Config.Aliases);
2450 Free (Config.Expansions);
2451 Free (Config.Prefixes);
2452 Free (Config.Sections);
2453 Free (Config.Switches);
2454 Unchecked_Free (Config);
2462 procedure Free (Cmd : in out Command_Line) is
2464 Free (Cmd.Expanded);
2465 Free (Cmd.Coalesce);
2469 end GNAT.Command_Line;