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 (if Concatenate then Parser.Current_Index else Arg'Last);
580 if Switches (Switches'First) = '*' then
582 -- Always prepend the switch character, so that users know that
583 -- this comes from a switch on the command line. This is
584 -- especially important when Concatenate is False, since
585 -- otherwise the current argument first character is lost.
589 Arg_Num => Parser.Current_Argument,
590 First => Parser.Current_Index,
592 Extra => Parser.Switch_Character);
593 Parser.Is_Switch (Parser.Current_Argument) := True;
594 Dummy := Goto_Next_Argument_In_Section (Parser);
600 Arg_Num => Parser.Current_Argument,
601 First => Parser.Current_Index,
603 Parser.Current_Index := End_Index + 1;
604 raise Invalid_Switch;
607 End_Index := Parser.Current_Index + Max_Length - 1;
610 Arg_Num => Parser.Current_Argument,
611 First => Parser.Current_Index,
615 when Parameter_With_Optional_Space =>
616 if End_Index < Arg'Last then
618 (Parser.The_Parameter,
619 Arg_Num => Parser.Current_Argument,
620 First => End_Index + 1,
622 Dummy := Goto_Next_Argument_In_Section (Parser);
624 elsif Parser.Current_Argument < Parser.Arg_Count
625 and then Parser.Section (Parser.Current_Argument + 1) /= 0
627 Parser.Current_Argument := Parser.Current_Argument + 1;
628 Parser.The_Separator := ' ';
630 (Parser.The_Parameter,
631 Arg_Num => Parser.Current_Argument,
632 First => Argument (Parser, Parser.Current_Argument)'First,
633 Last => Argument (Parser, Parser.Current_Argument)'Last);
634 Parser.Is_Switch (Parser.Current_Argument) := True;
635 Dummy := Goto_Next_Argument_In_Section (Parser);
638 Parser.Current_Index := End_Index + 1;
639 raise Invalid_Parameter;
642 when Parameter_With_Space_Or_Equal =>
644 -- If the switch is of the form <switch>=xxx
646 if End_Index < Arg'Last then
648 if Arg (End_Index + 1) = '='
649 and then End_Index + 1 < Arg'Last
651 Parser.The_Separator := '=';
653 (Parser.The_Parameter,
654 Arg_Num => Parser.Current_Argument,
655 First => End_Index + 2,
657 Dummy := Goto_Next_Argument_In_Section (Parser);
659 Parser.Current_Index := End_Index + 1;
660 raise Invalid_Parameter;
663 -- If the switch is of the form <switch> xxx
665 elsif Parser.Current_Argument < Parser.Arg_Count
666 and then Parser.Section (Parser.Current_Argument + 1) /= 0
668 Parser.Current_Argument := Parser.Current_Argument + 1;
669 Parser.The_Separator := ' ';
671 (Parser.The_Parameter,
672 Arg_Num => Parser.Current_Argument,
673 First => Argument (Parser, Parser.Current_Argument)'First,
674 Last => Argument (Parser, Parser.Current_Argument)'Last);
675 Parser.Is_Switch (Parser.Current_Argument) := True;
676 Dummy := Goto_Next_Argument_In_Section (Parser);
679 Parser.Current_Index := End_Index + 1;
680 raise Invalid_Parameter;
683 when Parameter_No_Space =>
685 if End_Index < Arg'Last then
687 (Parser.The_Parameter,
688 Arg_Num => Parser.Current_Argument,
689 First => End_Index + 1,
691 Dummy := Goto_Next_Argument_In_Section (Parser);
694 Parser.Current_Index := End_Index + 1;
695 raise Invalid_Parameter;
698 when Parameter_Optional =>
700 if End_Index < Arg'Last then
702 (Parser.The_Parameter,
703 Arg_Num => Parser.Current_Argument,
704 First => End_Index + 1,
708 Dummy := Goto_Next_Argument_In_Section (Parser);
710 when Parameter_None =>
712 if Concatenate or else End_Index = Arg'Last then
713 Parser.Current_Index := End_Index + 1;
716 -- If Concatenate is False and the full argument is not
717 -- recognized as a switch, this is an invalid switch.
719 if Switches (Switches'First) = '*' then
722 Arg_Num => Parser.Current_Argument,
725 Parser.Is_Switch (Parser.Current_Argument) := True;
726 Dummy := Goto_Next_Argument_In_Section (Parser);
732 Arg_Num => Parser.Current_Argument,
733 First => Parser.Current_Index,
735 Parser.Current_Index := Arg'Last + 1;
736 raise Invalid_Switch;
740 return Switches (Index_Switches);
744 -----------------------------------
745 -- Goto_Next_Argument_In_Section --
746 -----------------------------------
748 function Goto_Next_Argument_In_Section
749 (Parser : Opt_Parser) return Boolean
752 Parser.Current_Argument := Parser.Current_Argument + 1;
754 if Parser.Current_Argument > Parser.Arg_Count
755 or else Parser.Section (Parser.Current_Argument) = 0
758 Parser.Current_Argument := Parser.Current_Argument + 1;
760 if Parser.Current_Argument > Parser.Arg_Count then
761 Parser.Current_Index := 1;
765 exit when Parser.Section (Parser.Current_Argument) =
766 Parser.Current_Section;
770 Parser.Current_Index :=
771 Argument (Parser, Parser.Current_Argument)'First;
774 end Goto_Next_Argument_In_Section;
780 procedure Goto_Section
781 (Name : String := "";
782 Parser : Opt_Parser := Command_Line_Parser)
787 Parser.In_Expansion := False;
790 Parser.Current_Argument := 1;
791 Parser.Current_Index := 1;
792 Parser.Current_Section := 1;
797 while Index <= Parser.Arg_Count loop
798 if Parser.Section (Index) = 0
799 and then Argument (Parser, Index) = Parser.Switch_Character & Name
801 Parser.Current_Argument := Index + 1;
802 Parser.Current_Index := 1;
804 if Parser.Current_Argument <= Parser.Arg_Count then
805 Parser.Current_Section :=
806 Parser.Section (Parser.Current_Argument);
814 Parser.Current_Argument := Positive'Last;
815 Parser.Current_Index := 2; -- so that Get_Argument returns nothing
818 ----------------------------
819 -- Initialize_Option_Scan --
820 ----------------------------
822 procedure Initialize_Option_Scan
823 (Switch_Char : Character := '-';
824 Stop_At_First_Non_Switch : Boolean := False;
825 Section_Delimiters : String := "")
828 Internal_Initialize_Option_Scan
829 (Parser => Command_Line_Parser,
830 Switch_Char => Switch_Char,
831 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
832 Section_Delimiters => Section_Delimiters);
833 end Initialize_Option_Scan;
835 ----------------------------
836 -- Initialize_Option_Scan --
837 ----------------------------
839 procedure Initialize_Option_Scan
840 (Parser : out Opt_Parser;
841 Command_Line : GNAT.OS_Lib.Argument_List_Access;
842 Switch_Char : Character := '-';
843 Stop_At_First_Non_Switch : Boolean := False;
844 Section_Delimiters : String := "")
849 if Command_Line = null then
850 Parser := new Opt_Parser_Data (CL.Argument_Count);
851 Internal_Initialize_Option_Scan
853 Switch_Char => Switch_Char,
854 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
855 Section_Delimiters => Section_Delimiters);
857 Parser := new Opt_Parser_Data (Command_Line'Length);
858 Parser.Arguments := Command_Line;
859 Internal_Initialize_Option_Scan
861 Switch_Char => Switch_Char,
862 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
863 Section_Delimiters => Section_Delimiters);
865 end Initialize_Option_Scan;
867 -------------------------------------
868 -- Internal_Initialize_Option_Scan --
869 -------------------------------------
871 procedure Internal_Initialize_Option_Scan
872 (Parser : Opt_Parser;
873 Switch_Char : Character;
874 Stop_At_First_Non_Switch : Boolean;
875 Section_Delimiters : String)
877 Section_Num : Section_Number;
878 Section_Index : Integer;
880 Delimiter_Found : Boolean;
883 pragma Warnings (Off, Discard);
886 Parser.Current_Argument := 0;
887 Parser.Current_Index := 0;
888 Parser.In_Expansion := False;
889 Parser.Switch_Character := Switch_Char;
890 Parser.Stop_At_First := Stop_At_First_Non_Switch;
891 Parser.Section := (others => 1);
893 -- If we are using sections, we have to preprocess the command line
894 -- to delimit them. A section can be repeated, so we just give each
895 -- item on the command line a section number
898 Section_Index := Section_Delimiters'First;
899 while Section_Index <= Section_Delimiters'Last loop
900 Last := Section_Index;
901 while Last <= Section_Delimiters'Last
902 and then Section_Delimiters (Last) /= ' '
907 Delimiter_Found := False;
908 Section_Num := Section_Num + 1;
910 for Index in 1 .. Parser.Arg_Count loop
911 if Argument (Parser, Index)(1) = Parser.Switch_Character
913 Argument (Parser, Index) = Parser.Switch_Character &
915 (Section_Index .. Last - 1)
917 Parser.Section (Index) := 0;
918 Delimiter_Found := True;
920 elsif Parser.Section (Index) = 0 then
921 Delimiter_Found := False;
923 elsif Delimiter_Found then
924 Parser.Section (Index) := Section_Num;
928 Section_Index := Last + 1;
929 while Section_Index <= Section_Delimiters'Last
930 and then Section_Delimiters (Section_Index) = ' '
932 Section_Index := Section_Index + 1;
936 Discard := Goto_Next_Argument_In_Section (Parser);
937 end Internal_Initialize_Option_Scan;
944 (Parser : Opt_Parser := Command_Line_Parser) return String
947 if Parser.The_Parameter.First > Parser.The_Parameter.Last then
948 return String'(1 .. 0 => ' ');
950 return Argument
(Parser
, Parser
.The_Parameter
.Arg_Num
)
951 (Parser
.The_Parameter
.First
.. Parser
.The_Parameter
.Last
);
960 (Parser
: Opt_Parser
:= Command_Line_Parser
) return Character
963 return Parser
.The_Separator
;
970 procedure Set_Parameter
971 (Variable
: out Parameter_Type
;
975 Extra
: Character := ASCII
.NUL
)
978 Variable
.Arg_Num
:= Arg_Num
;
979 Variable
.First
:= First
;
980 Variable
.Last
:= Last
;
981 Variable
.Extra
:= Extra
;
984 ---------------------
985 -- Start_Expansion --
986 ---------------------
988 procedure Start_Expansion
989 (Iterator
: out Expansion_Iterator
;
991 Directory
: String := "";
992 Basic_Regexp
: Boolean := True)
994 Directory_Separator
: Character;
995 pragma Import
(C
, Directory_Separator
, "__gnat_dir_separator");
997 First
: Positive := Pattern
'First;
998 Pat
: String := Pattern
;
1001 Canonical_Case_File_Name
(Pat
);
1002 Iterator
.Current_Depth
:= 1;
1004 -- If Directory is unspecified, use the current directory ("./" or ".\")
1006 if Directory
= "" then
1007 Iterator
.Dir_Name
(1 .. 2) := "." & Directory_Separator
;
1008 Iterator
.Start
:= 3;
1011 Iterator
.Dir_Name
(1 .. Directory
'Length) := Directory
;
1012 Iterator
.Start
:= Directory
'Length + 1;
1013 Canonical_Case_File_Name
(Iterator
.Dir_Name
(1 .. Directory
'Length));
1015 -- Make sure that the last character is a directory separator
1017 if Directory
(Directory
'Last) /= Directory_Separator
then
1018 Iterator
.Dir_Name
(Iterator
.Start
) := Directory_Separator
;
1019 Iterator
.Start
:= Iterator
.Start
+ 1;
1023 Iterator
.Levels
(1).Name_Last
:= Iterator
.Start
- 1;
1025 -- Open the initial Directory, at depth 1
1027 GNAT
.Directory_Operations
.Open
1028 (Iterator
.Levels
(1).Dir
, Iterator
.Dir_Name
(1 .. Iterator
.Start
- 1));
1030 -- If in the current directory and the pattern starts with "./" or ".\",
1031 -- drop the "./" or ".\" from the pattern.
1033 if Directory
= "" and then Pat
'Length > 2
1034 and then Pat
(Pat
'First) = '.'
1035 and then Pat
(Pat
'First + 1) = Directory_Separator
1037 First
:= Pat
'First + 2;
1041 GNAT
.Regexp
.Compile
(Pat
(First
.. Pat
'Last), Basic_Regexp
, True);
1043 Iterator
.Maximum_Depth
:= 1;
1045 -- Maximum_Depth is equal to 1 plus the number of directory separators
1048 for Index
in First
.. Pat
'Last loop
1049 if Pat
(Index
) = Directory_Separator
then
1050 Iterator
.Maximum_Depth
:= Iterator
.Maximum_Depth
+ 1;
1051 exit when Iterator
.Maximum_Depth
= Max_Depth
;
1054 end Start_Expansion
;
1060 procedure Free
(Parser
: in out Opt_Parser
) is
1061 procedure Unchecked_Free
is new Ada
.Unchecked_Deallocation
1062 (Opt_Parser_Data
, Opt_Parser
);
1065 and then Parser
/= Command_Line_Parser
1067 Free
(Parser
.Arguments
);
1068 Unchecked_Free
(Parser
);
1076 procedure Define_Alias
1077 (Config
: in out Command_Line_Configuration
;
1082 if Config
= null then
1083 Config
:= new Command_Line_Configuration_Record
;
1086 Add
(Config
.Aliases
, new String'(Switch));
1087 Add (Config.Expansions, new String'(Expanded
));
1094 procedure Define_Prefix
1095 (Config
: in out Command_Line_Configuration
;
1099 if Config
= null then
1100 Config
:= new Command_Line_Configuration_Record
;
1103 Add
(Config
.Prefixes
, new String'(Prefix));
1110 procedure Define_Switch
1111 (Config : in out Command_Line_Configuration;
1115 if Config = null then
1116 Config := new Command_Line_Configuration_Record;
1119 Add (Config.Switches, new String'(Switch
));
1122 --------------------
1123 -- Define_Section --
1124 --------------------
1126 procedure Define_Section
1127 (Config
: in out Command_Line_Configuration
;
1131 if Config
= null then
1132 Config
:= new Command_Line_Configuration_Record
;
1135 Add
(Config
.Sections
, new String'(Section));
1142 function Get_Switches
1143 (Config : Command_Line_Configuration;
1144 Switch_Char : Character)
1147 Ret : Ada.Strings.Unbounded.Unbounded_String;
1148 use type Ada.Strings.Unbounded.Unbounded_String;
1151 if Config = null or else Config.Switches = null then
1155 for J in Config.Switches'Range loop
1156 if Config.Switches (J) (Config.Switches (J)'First) = Switch_Char then
1160 (Config.Switches (J)'First + 1 .. Config.Switches (J)'Last);
1162 Ret := Ret & " " & Config.Switches (J).all;
1166 return Ada.Strings.Unbounded.To_String (Ret);
1169 -----------------------
1170 -- Set_Configuration --
1171 -----------------------
1173 procedure Set_Configuration
1174 (Cmd : in out Command_Line;
1175 Config : Command_Line_Configuration)
1178 Cmd.Config := Config;
1179 end Set_Configuration;
1181 -----------------------
1182 -- Get_Configuration --
1183 -----------------------
1185 function Get_Configuration
1186 (Cmd : Command_Line) return Command_Line_Configuration is
1189 end Get_Configuration;
1191 ----------------------
1192 -- Set_Command_Line --
1193 ----------------------
1195 procedure Set_Command_Line
1196 (Cmd : in out Command_Line;
1198 Getopt_Description : String := "";
1199 Switch_Char : Character := '-')
1201 Tmp : Argument_List_Access;
1202 Parser : Opt_Parser;
1204 Section : String_Access := null;
1206 function Real_Full_Switch
1208 Parser : Opt_Parser) return String;
1209 -- Ensure that the returned switch value contains the
1210 -- Switch_Char prefix if needed.
1212 ----------------------
1213 -- Real_Full_Switch --
1214 ----------------------
1216 function Real_Full_Switch
1218 Parser : Opt_Parser) return String
1222 return Full_Switch (Parser);
1224 return Switch_Char & Full_Switch (Parser);
1226 end Real_Full_Switch;
1228 -- Start of processing for Set_Command_Line
1231 Free (Cmd.Expanded);
1234 if Switches /= "" then
1235 Tmp := Argument_String_To_List (Switches);
1236 Initialize_Option_Scan (Parser, Tmp, Switch_Char);
1240 S := Getopt (Switches => "* " & Getopt_Description,
1241 Concatenate => False,
1243 exit when S = ASCII.NUL;
1246 Sw : constant String :=
1247 Real_Full_Switch (S, Parser);
1248 Is_Section : Boolean := False;
1251 if Cmd.Config /= null
1252 and then Cmd.Config.Sections /= null
1255 for S in Cmd.Config.Sections'Range loop
1256 if Sw = Cmd.Config.Sections (S).all then
1257 Section := Cmd.Config.Sections (S);
1260 exit Section_Search;
1262 end loop Section_Search;
1265 if not Is_Section then
1266 if Section = null then
1268 -- Work around some weird cases: some switches may
1269 -- expect parameters, but have the same value as
1270 -- longer switches: -gnaty3 (-gnaty, parameter=3) and
1271 -- -gnatya (-gnatya, no parameter).
1273 -- So we are calling add_switch here with parameter
1274 -- attached. This will be anyway correctly handled by
1275 -- Add_Switch if -gnaty3 is actually provided.
1277 if Separator (Parser) = ASCII.NUL then
1279 (Cmd, Sw & Parameter (Parser), "", ASCII.NUL);
1282 (Cmd, Sw, Parameter (Parser), Separator (Parser));
1285 if Separator (Parser) = ASCII.NUL then
1287 (Cmd, Sw & Parameter (Parser), "",
1302 when Invalid_Parameter =>
1304 -- Add it with no parameter, if that's the way the user
1307 -- Specify the separator in all cases, as the switch might
1308 -- need to be unaliased, and the alias might contain
1309 -- switches with parameters.
1311 if Section = null then
1313 (Cmd, Switch_Char & Full_Switch (Parser),
1314 Separator => Separator (Parser));
1317 (Cmd, Switch_Char & Full_Switch (Parser),
1318 Separator => Separator (Parser),
1319 Section => Section.all);
1326 end Set_Command_Line;
1335 Substring : String) return Boolean is
1337 return Index + Substring'Length - 1 <= Type_Str'Last
1338 and then Type_Str (Index .. Index + Substring'Length - 1) = Substring;
1341 ------------------------
1342 -- Can_Have_Parameter --
1343 ------------------------
1345 function Can_Have_Parameter (S : String) return Boolean is
1347 if S'Length <= 1 then
1352 when '!' | ':' | '?
' | '=' =>
1357 end Can_Have_Parameter;
1359 -----------------------
1360 -- Require_Parameter --
1361 -----------------------
1363 function Require_Parameter (S : String) return Boolean is
1365 if S'Length <= 1 then
1370 when '!' | ':' | '=' =>
1375 end Require_Parameter;
1381 function Actual_Switch (S : String) return String is
1383 if S'Length <= 1 then
1388 when '!' | ':' | '?
' | '=' =>
1389 return S (S'First .. S'Last - 1);
1395 ----------------------------
1396 -- For_Each_Simple_Switch --
1397 ----------------------------
1399 procedure For_Each_Simple_Switch
1400 (Cmd : Command_Line;
1402 Parameter : String := "";
1403 Unalias : Boolean := True)
1405 function Group_Analysis
1407 Group : String) return Boolean;
1408 -- Perform the analysis of a group of switches
1410 --------------------
1411 -- Group_Analysis --
1412 --------------------
1414 function Group_Analysis
1416 Group : String) return Boolean
1423 while Idx <= Group'Last loop
1426 for S in Cmd.Config.Switches'Range loop
1428 Sw : constant String :=
1430 (Cmd.Config.Switches (S).all);
1431 Full : constant String :=
1432 Prefix & Group (Idx .. Group'Last);
1437 if Sw'Length >= Prefix'Length
1439 -- Verify that sw starts with Prefix
1441 and then Looking_At (Sw, Sw'First, Prefix)
1443 -- Verify that the group starts with sw
1445 and then Looking_At (Full, Full'First, Sw)
1447 Last := Idx + Sw'Length - Prefix'Length - 1;
1450 if Can_Have_Parameter (Cmd.Config.Switches (S).all) then
1452 -- Include potential parameter to the recursive call.
1453 -- Only numbers are allowed.
1455 while Last < Group'Last
1456 and then Group (Last + 1) in '0' .. '9'
1462 if not Require_Parameter (Cmd.Config.Switches (S).all)
1463 or else Last >= Param
1465 if Idx = Group'First
1466 and then Last = Group'Last
1467 and then Last < Param
1469 -- The group only concerns a single switch. Do not
1470 -- perform recursive call.
1472 -- Note that we still perform a recursive call if
1473 -- a parameter is detected in the switch, as this
1474 -- is a way to correctly identify such a parameter
1482 -- Recursive call, using the detected parameter if any
1484 if Last >= Param then
1485 For_Each_Simple_Switch
1487 Prefix & Group (Idx .. Param - 1),
1488 Group (Param .. Last));
1490 For_Each_Simple_Switch
1491 (Cmd, Prefix & Group (Idx .. Last), "");
1502 For_Each_Simple_Switch (Cmd, Prefix & Group (Idx), "");
1511 -- First determine if the switch corresponds to one belonging to the
1512 -- configuration. If so, run callback and exit.
1514 if Cmd.Config /= null and then Cmd.Config.Switches /= null then
1515 for S in Cmd.Config.Switches'Range loop
1517 Config_Switch : String renames Cmd.Config.Switches (S).all;
1519 if Actual_Switch (Config_Switch) = Switch
1521 ((Can_Have_Parameter (Config_Switch)
1522 and then Parameter /= "")
1524 (not Require_Parameter (Config_Switch)
1525 and then Parameter = ""))
1527 Callback (Switch, Parameter);
1534 -- If adding a switch that can in fact be expanded through aliases,
1535 -- add separately each of its expansions.
1537 -- This takes care of expansions like "-T" -> "-gnatwrs", where the
1538 -- alias and its expansion do not have the same prefix. Given the order
1539 -- in which we do things here, the expansion of the alias will itself
1540 -- be checked for a common prefix and split into simple switches.
1543 and then Cmd.Config /= null
1544 and then Cmd.Config.Aliases /= null
1546 for A in Cmd.Config.Aliases'Range loop
1547 if Cmd.Config.Aliases (A).all = Switch and then Parameter = "" then
1548 For_Each_Simple_Switch
1549 (Cmd, Cmd.Config.Expansions (A).all, "");
1555 -- If adding a switch grouping several switches, add each of the simple
1556 -- switches instead.
1558 if Cmd.Config /= null and then Cmd.Config.Prefixes /= null then
1559 for P in Cmd.Config.Prefixes'Range loop
1560 if Switch'Length > Cmd.Config.Prefixes (P)'Length + 1
1562 (Switch, Switch'First, Cmd.Config.Prefixes (P).all)
1564 -- Alias expansion will be done recursively
1566 if Cmd.Config.Switches = null then
1567 for S in Switch'First + Cmd.Config.Prefixes (P)'Length
1570 For_Each_Simple_Switch
1571 (Cmd, Cmd.Config.Prefixes (P).all & Switch (S), "");
1576 elsif Group_Analysis
1577 (Cmd.Config.Prefixes (P).all,
1579 (Switch'First + Cmd.Config.Prefixes (P)'Length
1582 -- Recursive calls already done on each switch of the group:
1583 -- Return without executing Callback.
1591 -- Test if added switch is a known switch with parameter attached
1594 and then Cmd.Config /= null
1595 and then Cmd.Config.Switches /= null
1597 for S in Cmd.Config.Switches'Range loop
1599 Sw : constant String :=
1600 Actual_Switch (Cmd.Config.Switches (S).all);
1605 -- Verify that switch starts with Sw
1606 -- What if the "verification" fails???
1608 if Switch'Length >= Sw'Length
1609 and then Looking_At (Switch, Switch'First, Sw)
1611 Param := Switch'First + Sw'Length - 1;
1614 if Can_Have_Parameter (Cmd.Config.Switches (S).all) then
1615 while Last < Switch'Last
1616 and then Switch (Last + 1) in '0' .. '9'
1622 -- If full Switch is a known switch with attached parameter
1623 -- then we use this parameter in the callback.
1625 if Last = Switch'Last then
1627 (Switch (Switch'First .. Param),
1628 Switch (Param + 1 .. Last));
1637 Callback (Switch, Parameter);
1638 end For_Each_Simple_Switch;
1644 procedure Add_Switch
1645 (Cmd : in out Command_Line;
1647 Parameter : String := "";
1648 Separator : Character := ' ';
1649 Section : String := "";
1650 Add_Before : Boolean := False)
1653 pragma Unreferenced (Success);
1656 (Cmd, Switch, Parameter, Separator, Section, Add_Before, Success);
1663 procedure Add_Switch
1664 (Cmd : in out Command_Line;
1666 Parameter : String := "";
1667 Separator : Character := ' ';
1668 Section : String := "";
1669 Add_Before : Boolean := False;
1670 Success : out Boolean)
1672 procedure Add_Simple_Switch (Simple : String; Param : String);
1673 -- Add a new switch that has had all its aliases expanded, and switches
1674 -- ungrouped. We know there are no more aliases in Switches.
1676 -----------------------
1677 -- Add_Simple_Switch --
1678 -----------------------
1680 procedure Add_Simple_Switch (Simple : String; Param : String) is
1682 if Cmd.Expanded = null then
1683 Cmd.Expanded := new Argument_List'(1 .. 1 => new String'(Simple));
1686 Cmd.Params := new Argument_List'
1687 (1 .. 1 => new String'(Separator & Param));
1690 Cmd.Params := new Argument_List'(1 .. 1 => null);
1693 if Section
= "" then
1694 Cmd
.Sections
:= new Argument_List
'(1 .. 1 => null);
1697 Cmd.Sections := new Argument_List'
1698 (1 .. 1 => new String'(Section));
1702 -- Do we already have this switch?
1704 for C in Cmd.Expanded'Range loop
1705 if Cmd.Expanded (C).all = Simple
1707 ((Cmd.Params (C) = null and then Param = "")
1709 (Cmd.Params (C) /= null
1710 and then Cmd.Params (C).all = Separator & Param))
1712 ((Cmd.Sections (C) = null and then Section = "")
1714 (Cmd.Sections (C) /= null
1715 and then Cmd.Sections (C).all = Section))
1721 -- Inserting at least one switch
1724 Add (Cmd.Expanded, new String'(Simple
), Add_Before
);
1729 new String'(Separator & Param),
1739 if Section = "" then
1747 new String'(Section
),
1751 end Add_Simple_Switch
;
1753 procedure Add_Simple_Switches
is
1754 new For_Each_Simple_Switch
(Add_Simple_Switch
);
1756 -- Start of processing for Add_Switch
1760 Add_Simple_Switches
(Cmd
, Switch
, Parameter
);
1761 Free
(Cmd
.Coalesce
);
1768 procedure Remove
(Line
: in out Argument_List_Access
; Index
: Integer) is
1769 Tmp
: Argument_List_Access
:= Line
;
1772 Line
:= new Argument_List
(Tmp
'First .. Tmp
'Last - 1);
1774 if Index
/= Tmp
'First then
1775 Line
(Tmp
'First .. Index
- 1) := Tmp
(Tmp
'First .. Index
- 1);
1780 if Index
/= Tmp
'Last then
1781 Line
(Index
.. Tmp
'Last - 1) := Tmp
(Index
+ 1 .. Tmp
'Last);
1784 Unchecked_Free
(Tmp
);
1792 (Line
: in out Argument_List_Access
;
1793 Str
: String_Access
;
1794 Before
: Boolean := False)
1796 Tmp
: Argument_List_Access
:= Line
;
1800 Line
:= new Argument_List
(Tmp
'First .. Tmp
'Last + 1);
1803 Line
(Tmp
'First) := Str
;
1804 Line
(Tmp
'First + 1 .. Tmp
'Last + 1) := Tmp
.all;
1806 Line
(Tmp
'Range) := Tmp
.all;
1807 Line
(Tmp
'Last + 1) := Str
;
1810 Unchecked_Free
(Tmp
);
1813 Line
:= new Argument_List
'(1 .. 1 => Str);
1821 procedure Remove_Switch
1822 (Cmd : in out Command_Line;
1824 Remove_All : Boolean := False;
1825 Has_Parameter : Boolean := False;
1826 Section : String := "")
1829 pragma Unreferenced (Success);
1831 Remove_Switch (Cmd, Switch, Remove_All, Has_Parameter, Section, Success);
1838 procedure Remove_Switch
1839 (Cmd : in out Command_Line;
1841 Remove_All : Boolean := False;
1842 Has_Parameter : Boolean := False;
1843 Section : String := "";
1844 Success : out Boolean)
1846 procedure Remove_Simple_Switch (Simple : String; Param : String);
1847 -- Removes a simple switch, with no aliasing or grouping
1849 --------------------------
1850 -- Remove_Simple_Switch --
1851 --------------------------
1853 procedure Remove_Simple_Switch (Simple : String; Param : String) is
1855 pragma Unreferenced (Param);
1858 if Cmd.Expanded /= null then
1859 C := Cmd.Expanded'First;
1860 while C <= Cmd.Expanded'Last loop
1861 if Cmd.Expanded (C).all = Simple
1864 or else (Cmd.Sections (C) = null
1865 and then Section = "")
1866 or else (Cmd.Sections (C) /= null
1867 and then Section = Cmd.Sections (C).all))
1868 and then (not Has_Parameter or else Cmd.Params (C) /= null)
1870 Remove (Cmd.Expanded, C);
1871 Remove (Cmd.Params, C);
1872 Remove (Cmd.Sections, C);
1875 if not Remove_All then
1884 end Remove_Simple_Switch;
1886 procedure Remove_Simple_Switches is
1887 new For_Each_Simple_Switch (Remove_Simple_Switch);
1889 -- Start of processing for Remove_Switch
1893 Remove_Simple_Switches (Cmd, Switch, "", Unalias => not Has_Parameter);
1894 Free (Cmd.Coalesce);
1901 procedure Remove_Switch
1902 (Cmd : in out Command_Line;
1905 Section : String := "")
1907 procedure Remove_Simple_Switch (Simple : String; Param : String);
1908 -- Removes a simple switch, with no aliasing or grouping
1910 --------------------------
1911 -- Remove_Simple_Switch --
1912 --------------------------
1914 procedure Remove_Simple_Switch (Simple : String; Param : String) is
1918 if Cmd.Expanded /= null then
1919 C := Cmd.Expanded'First;
1920 while C <= Cmd.Expanded'Last loop
1921 if Cmd.Expanded (C).all = Simple
1923 ((Cmd.Sections (C) = null
1924 and then Section = "")
1926 (Cmd.Sections (C) /= null
1927 and then Section = Cmd.Sections (C).all))
1929 ((Cmd.Params (C) = null and then Param = "")
1931 (Cmd.Params (C) /= null
1934 -- Ignore the separator stored in Parameter
1936 Cmd.Params (C) (Cmd.Params (C)'First + 1
1937 .. Cmd.Params (C)'Last) =
1940 Remove (Cmd.Expanded, C);
1941 Remove (Cmd.Params, C);
1942 Remove (Cmd.Sections, C);
1944 -- The switch is necessarily unique by construction of
1954 end Remove_Simple_Switch;
1956 procedure Remove_Simple_Switches is
1957 new For_Each_Simple_Switch (Remove_Simple_Switch);
1959 -- Start of processing for Remove_Switch
1962 Remove_Simple_Switches (Cmd, Switch, Parameter);
1963 Free (Cmd.Coalesce);
1966 --------------------
1967 -- Group_Switches --
1968 --------------------
1970 procedure Group_Switches
1971 (Cmd : Command_Line;
1972 Result : Argument_List_Access;
1973 Sections : Argument_List_Access;
1974 Params : Argument_List_Access)
1976 function Compatible_Parameter (Param : String_Access) return Boolean;
1977 -- True when the parameter can be part of a group
1979 --------------------------
1980 -- Compatible_Parameter --
1981 --------------------------
1983 function Compatible_Parameter (Param : String_Access) return Boolean is
1987 if Param = null then
1990 -- We need parameters without separators
1992 elsif Param (Param'First) /= ASCII.NUL then
1995 -- Parameters must be all digits
1998 for J in Param'First + 1 .. Param'Last loop
1999 if Param (J) not in '0' .. '9' then
2006 end Compatible_Parameter;
2008 -- Local declarations
2010 Group : Ada.Strings.Unbounded.Unbounded_String;
2012 use type Ada.Strings.Unbounded.Unbounded_String;
2014 -- Start of processing for Group_Switches
2017 if Cmd.Config = null
2018 or else Cmd.Config.Prefixes = null
2023 for P in Cmd.Config.Prefixes'Range loop
2024 Group := Ada.Strings.Unbounded.Null_Unbounded_String;
2027 for C in Result'Range loop
2028 if Result (C) /= null
2029 and then Compatible_Parameter (Params (C))
2031 (Result (C).all, Result (C)'First, Cmd.Config.Prefixes (P).all)
2033 -- If we are still in the same section, group the switches
2037 (Sections (C) = null
2038 and then Sections (First) = null)
2040 (Sections (C) /= null
2041 and then Sections (First) /= null
2042 and then Sections (C).all = Sections (First).all)
2047 (Result (C)'First + Cmd.Config.Prefixes (P)'Length ..
2050 if Params (C) /= null then
2053 Params (C) (Params (C)'First + 1 .. Params (C)'Last);
2064 -- We changed section: we put the grouped switches to the
2065 -- first place, on continue with the new section.
2069 (Cmd
.Config
.Prefixes
(P
).all &
2070 Ada
.Strings
.Unbounded
.To_String
(Group
));
2072 Ada
.Strings
.Unbounded
.To_Unbounded_String
2074 (Result
(C
)'First + Cmd
.Config
.Prefixes
(P
)'Length ..
2084 (Cmd.Config.Prefixes (P).all &
2085 Ada.Strings.Unbounded.To_String (Group));
2090 --------------------
2091 -- Alias_Switches --
2092 --------------------
2094 procedure Alias_Switches
2095 (Cmd : Command_Line;
2096 Result : Argument_List_Access;
2097 Params : Argument_List_Access)
2102 procedure Check_Cb (Switch : String; Param : String);
2103 -- Comment required ???
2105 procedure Remove_Cb (Switch : String; Param : String);
2106 -- Comment required ???
2112 procedure Check_Cb (Switch : String; Param : String) is
2115 for E in Result'Range loop
2116 if Result (E) /= null
2119 or else Params (E) (Params (E)'First + 1
2120 .. Params (E)'Last) = Param)
2121 and then Result (E).all = Switch
2135 procedure Remove_Cb (Switch : String; Param : String) is
2137 for E in Result'Range loop
2138 if Result (E) /= null
2141 or else Params (E) (Params (E)'First + 1
2142 .. Params (E)'Last) = Param)
2143 and then Result (E).all = Switch
2155 procedure Check_All is new For_Each_Simple_Switch (Check_Cb);
2156 procedure Remove_All is new For_Each_Simple_Switch (Remove_Cb);
2158 -- Start of processing for Alias_Switches
2161 if Cmd.Config = null
2162 or else Cmd.Config.Aliases = null
2167 for A in Cmd.Config.Aliases'Range loop
2169 -- Compute the various simple switches that make up the alias. We
2170 -- split the expansion into as many simple switches as possible, and
2171 -- then check whether the expanded command line has all of them.
2174 Check_All (Cmd, Cmd.Config.Expansions (A).all);
2177 First := Integer'Last;
2178 Remove_All (Cmd, Cmd.Config.Expansions (A).all);
2179 Result (First) := new String'(Cmd
.Config
.Aliases
(A
).all);
2188 procedure Sort_Sections
2189 (Line
: GNAT
.OS_Lib
.Argument_List_Access
;
2190 Sections
: GNAT
.OS_Lib
.Argument_List_Access
;
2191 Params
: GNAT
.OS_Lib
.Argument_List_Access
)
2193 Sections_List
: Argument_List_Access
:=
2194 new Argument_List
'(1 .. 1 => null);
2196 Old_Line : constant Argument_List := Line.all;
2197 Old_Sections : constant Argument_List := Sections.all;
2198 Old_Params : constant Argument_List := Params.all;
2206 -- First construct a list of all sections
2208 for E in Line'Range loop
2209 if Sections (E) /= null then
2211 for S in Sections_List'Range loop
2212 if (Sections_List (S) = null and then Sections (E) = null)
2214 (Sections_List (S) /= null
2215 and then Sections (E) /= null
2216 and then Sections_List (S).all = Sections (E).all)
2224 Add (Sections_List, Sections (E));
2229 Index := Line'First;
2231 for S in Sections_List'Range loop
2232 for E in Old_Line'Range loop
2233 if (Sections_List (S) = null and then Old_Sections (E) = null)
2235 (Sections_List (S) /= null
2236 and then Old_Sections (E) /= null
2237 and then Sections_List (S).all = Old_Sections (E).all)
2239 Line (Index) := Old_Line (E);
2240 Sections (Index) := Old_Sections (E);
2241 Params (Index) := Old_Params (E);
2253 (Cmd : in out Command_Line;
2254 Iter : in out Command_Line_Iterator;
2258 if Cmd.Expanded = null then
2263 -- Reorder the expanded line so that sections are grouped
2265 Sort_Sections (Cmd.Expanded, Cmd.Sections, Cmd.Params);
2267 -- Coalesce the switches as much as possible
2270 and then Cmd.Coalesce = null
2272 Cmd.Coalesce := new Argument_List (Cmd.Expanded'Range);
2273 for E in Cmd.Expanded'Range loop
2274 Cmd.Coalesce (E) := new String'(Cmd
.Expanded
(E
).all);
2277 Cmd
.Coalesce_Sections
:= new Argument_List
(Cmd
.Sections
'Range);
2278 for E
in Cmd
.Sections
'Range loop
2279 Cmd
.Coalesce_Sections
(E
) :=
2280 (if Cmd
.Sections
(E
) = null then null
2281 else new String'(Cmd.Sections (E).all));
2284 Cmd.Coalesce_Params := new Argument_List (Cmd.Params'Range);
2285 for E in Cmd.Params'Range loop
2286 Cmd.Coalesce_Params (E) :=
2287 (if Cmd.Params (E) = null then null
2288 else new String'(Cmd
.Params
(E
).all));
2291 -- Not a clone, since we will not modify the parameters anyway
2293 Alias_Switches
(Cmd
, Cmd
.Coalesce
, Cmd
.Coalesce_Params
);
2295 (Cmd
, Cmd
.Coalesce
, Cmd
.Coalesce_Sections
, Cmd
.Coalesce_Params
);
2299 Iter
.List
:= Cmd
.Expanded
;
2300 Iter
.Params
:= Cmd
.Params
;
2301 Iter
.Sections
:= Cmd
.Sections
;
2303 Iter
.List
:= Cmd
.Coalesce
;
2304 Iter
.Params
:= Cmd
.Coalesce_Params
;
2305 Iter
.Sections
:= Cmd
.Coalesce_Sections
;
2308 if Iter
.List
= null then
2309 Iter
.Current
:= Integer'Last;
2311 Iter
.Current
:= Iter
.List
'First;
2313 while Iter
.Current
<= Iter
.List
'Last
2314 and then Iter
.List
(Iter
.Current
) = null
2316 Iter
.Current
:= Iter
.Current
+ 1;
2321 --------------------
2322 -- Current_Switch --
2323 --------------------
2325 function Current_Switch
(Iter
: Command_Line_Iterator
) return String is
2327 return Iter
.List
(Iter
.Current
).all;
2330 --------------------
2331 -- Is_New_Section --
2332 --------------------
2334 function Is_New_Section
(Iter
: Command_Line_Iterator
) return Boolean is
2335 Section
: constant String := Current_Section
(Iter
);
2337 if Iter
.Sections
= null then
2339 elsif Iter
.Current
= Iter
.Sections
'First
2340 or else Iter
.Sections
(Iter
.Current
- 1) = null
2342 return Section
/= "";
2345 return Section
/= Iter
.Sections
(Iter
.Current
- 1).all;
2348 ---------------------
2349 -- Current_Section --
2350 ---------------------
2352 function Current_Section
(Iter
: Command_Line_Iterator
) return String is
2354 if Iter
.Sections
= null
2355 or else Iter
.Current
> Iter
.Sections
'Last
2356 or else Iter
.Sections
(Iter
.Current
) = null
2361 return Iter
.Sections
(Iter
.Current
).all;
2362 end Current_Section
;
2364 -----------------------
2365 -- Current_Separator --
2366 -----------------------
2368 function Current_Separator
(Iter
: Command_Line_Iterator
) return String is
2370 if Iter
.Params
= null
2371 or else Iter
.Current
> Iter
.Params
'Last
2372 or else Iter
.Params
(Iter
.Current
) = null
2378 Sep
: constant Character :=
2379 Iter
.Params
(Iter
.Current
) (Iter
.Params
(Iter
.Current
)'First);
2381 if Sep
= ASCII
.NUL
then
2388 end Current_Separator
;
2390 -----------------------
2391 -- Current_Parameter --
2392 -----------------------
2394 function Current_Parameter
(Iter
: Command_Line_Iterator
) return String is
2396 if Iter
.Params
= null
2397 or else Iter
.Current
> Iter
.Params
'Last
2398 or else Iter
.Params
(Iter
.Current
) = null
2404 P
: constant String := Iter
.Params
(Iter
.Current
).all;
2409 return P
(P
'First + 1 .. P
'Last);
2412 end Current_Parameter
;
2418 function Has_More
(Iter
: Command_Line_Iterator
) return Boolean is
2420 return Iter
.List
/= null and then Iter
.Current
<= Iter
.List
'Last;
2427 procedure Next
(Iter
: in out Command_Line_Iterator
) is
2429 Iter
.Current
:= Iter
.Current
+ 1;
2430 while Iter
.Current
<= Iter
.List
'Last
2431 and then Iter
.List
(Iter
.Current
) = null
2433 Iter
.Current
:= Iter
.Current
+ 1;
2441 procedure Free
(Config
: in out Command_Line_Configuration
) is
2443 if Config
/= null then
2444 Free
(Config
.Aliases
);
2445 Free
(Config
.Expansions
);
2446 Free
(Config
.Prefixes
);
2447 Free
(Config
.Sections
);
2448 Free
(Config
.Switches
);
2449 Unchecked_Free
(Config
);
2457 procedure Free
(Cmd
: in out Command_Line
) is
2459 Free
(Cmd
.Expanded
);
2460 Free
(Cmd
.Coalesce
);
2464 end GNAT
.Command_Line
;