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-2008, 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 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 with Ada.Unchecked_Deallocation;
35 with Ada.Strings.Unbounded;
37 with GNAT.OS_Lib; use GNAT.OS_Lib;
39 package body GNAT.Command_Line is
41 package CL renames Ada.Command_Line;
43 type Switch_Parameter_Type is
45 Parameter_With_Optional_Space, -- ':' in getopt
46 Parameter_With_Space_Or_Equal, -- '=' in getopt
47 Parameter_No_Space, -- '!' in getopt
48 Parameter_Optional); -- '?' in getopt
50 procedure Set_Parameter
51 (Variable : out Parameter_Type;
55 Extra : Character := ASCII.NUL);
56 pragma Inline (Set_Parameter);
57 -- Set the parameter that will be returned by Parameter below
58 -- Parameters need to be defined ???
60 function Goto_Next_Argument_In_Section (Parser : Opt_Parser) return Boolean;
61 -- Go to the next argument on the command line. If we are at the end of
62 -- the current section, we want to make sure there is no other identical
63 -- section on the command line (there might be multiple instances of
64 -- -largs). Returns True iff there is another argument.
66 function Get_File_Names_Case_Sensitive return Integer;
67 pragma Import (C, Get_File_Names_Case_Sensitive,
68 "__gnat_get_file_names_case_sensitive");
70 File_Names_Case_Sensitive : constant Boolean :=
71 Get_File_Names_Case_Sensitive /= 0;
73 procedure Canonical_Case_File_Name (S : in out String);
74 -- Given a file name, converts it to canonical case form. For systems where
75 -- file names are case sensitive, this procedure has no effect. If file
76 -- names are not case sensitive (i.e. for example if you have the file
77 -- "xyz.adb", you can refer to it as XYZ.adb or XyZ.AdB), then this call
78 -- converts the given string to canonical all lower case form, so that two
79 -- file names compare equal if they refer to the same file.
81 procedure Internal_Initialize_Option_Scan
83 Switch_Char : Character;
84 Stop_At_First_Non_Switch : Boolean;
85 Section_Delimiters : String);
86 -- Initialize Parser, which must have been allocated already
88 function Argument (Parser : Opt_Parser; Index : Integer) return String;
89 -- Return the index-th command line argument
91 procedure Find_Longest_Matching_Switch
94 Index_In_Switches : out Integer;
95 Switch_Length : out Integer;
96 Param : out Switch_Parameter_Type);
97 -- return the Longest switch from Switches that matches at least
98 -- partially Arg. Index_In_Switches is set to 0 if none matches
100 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
101 (Argument_List, Argument_List_Access);
103 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
104 (Command_Line_Configuration_Record, Command_Line_Configuration);
106 procedure Remove (Line : in out Argument_List_Access; Index : Integer);
107 -- Remove a specific element from Line
110 (Line : in out Argument_List_Access;
111 Str : String_Access);
112 -- Append a new element to Line
114 function Can_Have_Parameter (S : String) return Boolean;
115 -- Tell if S can have a parameter.
117 function Require_Parameter (S : String) return Boolean;
118 -- Tell if S requires a paramter.
120 function Actual_Switch (S : String) return String;
121 -- Remove any possible trailing '!', ':', '?' and '='
124 with procedure Callback (Simple_Switch : String; Parameter : String);
125 procedure For_Each_Simple_Switch
128 Parameter : String := "";
129 Unalias : Boolean := True);
130 -- Breaks Switch into as simple switches as possible (expanding aliases and
131 -- ungrouping common prefixes when possible), and call Callback for each of
134 procedure Sort_Sections
135 (Line : GNAT.OS_Lib.Argument_List_Access;
136 Sections : GNAT.OS_Lib.Argument_List_Access;
137 Params : GNAT.OS_Lib.Argument_List_Access);
138 -- Reorder the command line switches so that the switches belonging to a
139 -- section are grouped together.
141 procedure Group_Switches
143 Result : Argument_List_Access;
144 Sections : Argument_List_Access;
145 Params : Argument_List_Access);
146 -- Group switches with common prefixes whenever possible.
147 -- Once they have been grouped, we also check items for possible aliasing
149 procedure Alias_Switches
151 Result : Argument_List_Access;
152 Params : Argument_List_Access);
153 -- When possible, replace or more switches by an alias, i.e. a shorter
159 Substring : String) return Boolean;
160 -- Return True if the characters starting at Index in Type_Str are
161 -- equivalent to Substring.
167 function Argument (Parser : Opt_Parser; Index : Integer) return String is
169 if Parser.Arguments /= null then
170 return Parser.Arguments (Index + Parser.Arguments'First - 1).all;
172 return CL.Argument (Index);
176 ------------------------------
177 -- Canonical_Case_File_Name --
178 ------------------------------
180 procedure Canonical_Case_File_Name (S : in out String) is
182 if not File_Names_Case_Sensitive then
183 for J in S'Range loop
184 if S (J) in 'A' .. 'Z' then
185 S (J) := Character'Val
186 (Character'Pos (S (J)) +
187 Character'Pos ('a') -
188 Character'Pos ('A'));
192 end Canonical_Case_File_Name;
198 function Expansion (Iterator : Expansion_Iterator) return String is
199 use GNAT.Directory_Operations;
200 type Pointer is access all Expansion_Iterator;
202 It : constant Pointer := Iterator'Unrestricted_Access;
203 S : String (1 .. 1024);
206 Current : Depth := It.Current_Depth;
210 -- It is assumed that a directory is opened at the current level.
211 -- Otherwise GNAT.Directory_Operations.Directory_Error will be raised
212 -- at the first call to Read.
215 Read (It.Levels (Current).Dir, S, Last);
217 -- If we have exhausted the directory, close it and go back one level
220 Close (It.Levels (Current).Dir);
222 -- If we are at level 1, we are finished; return an empty string
225 return String'(1 .. 0 => ' ');
227 -- Otherwise continue with the directory at the previous level
229 Current := Current - 1;
230 It.Current_Depth := Current;
233 -- If this is a directory, that is neither "." or "..", attempt to
234 -- go to the next level.
237 (It.Dir_Name (1 .. It.Levels (Current).Name_Last) & S (1 .. Last))
238 and then S (1 .. Last) /= "."
239 and then S (1 .. Last) /= ".."
241 -- We can go to the next level only if we have not reached the
244 if Current < It.Maximum_Depth then
245 NL := It.Levels (Current).Name_Last;
247 -- And if relative path of this new directory is not too long
249 if NL + Last + 1 < Max_Path_Length then
250 Current := Current + 1;
251 It.Current_Depth := Current;
252 It.Dir_Name (NL + 1 .. NL + Last) := S (1 .. Last);
254 It.Dir_Name (NL) := Directory_Separator;
255 It.Levels (Current).Name_Last := NL;
256 Canonical_Case_File_Name (It.Dir_Name (1 .. NL));
258 -- Open the new directory, and read from it
260 GNAT.Directory_Operations.Open
261 (It.Levels (Current).Dir, It.Dir_Name (1 .. NL));
265 -- If not a directory, check the relative path against the pattern
270 It.Dir_Name (It.Start .. It.Levels (Current).Name_Last)
273 Canonical_Case_File_Name (Name);
275 -- If it matches return the relative path
277 if GNAT.Regexp.Match (Name, Iterator.Regexp) then
290 (Parser : Opt_Parser := Command_Line_Parser) return String
293 if Parser.The_Switch.Extra = ASCII.NUL then
294 return Argument (Parser, Parser.The_Switch.Arg_Num)
295 (Parser.The_Switch.First .. Parser.The_Switch.Last);
297 return Parser.The_Switch.Extra
298 & Argument (Parser, Parser.The_Switch.Arg_Num)
299 (Parser.The_Switch.First .. Parser.The_Switch.Last);
307 function Get_Argument
308 (Do_Expansion : Boolean := False;
309 Parser : Opt_Parser := Command_Line_Parser) return String
312 if Parser.In_Expansion then
314 S : constant String := Expansion (Parser.Expansion_It);
316 if S'Length /= 0 then
319 Parser.In_Expansion := False;
324 if Parser.Current_Argument > Parser.Arg_Count then
326 -- If this is the first time this function is called
328 if Parser.Current_Index = 1 then
329 Parser.Current_Argument := 1;
330 while Parser.Current_Argument <= Parser.Arg_Count
331 and then Parser.Section (Parser.Current_Argument) /=
332 Parser.Current_Section
334 Parser.Current_Argument := Parser.Current_Argument + 1;
337 return String'(1 .. 0 => ' ');
340 elsif Parser.Section (Parser.Current_Argument) = 0 then
341 while Parser.Current_Argument <= Parser.Arg_Count
342 and then Parser.Section (Parser.Current_Argument) /=
343 Parser.Current_Section
345 Parser.Current_Argument := Parser.Current_Argument + 1;
349 Parser.Current_Index := Integer'Last;
351 while Parser.Current_Argument <= Parser.Arg_Count
352 and then Parser.Is_Switch (Parser.Current_Argument)
354 Parser.Current_Argument := Parser.Current_Argument + 1;
357 if Parser.Current_Argument > Parser.Arg_Count then
358 return String'(1 .. 0 => ' ');
359 elsif Parser.Section (Parser.Current_Argument) = 0 then
360 return Get_Argument (Do_Expansion);
363 Parser.Current_Argument := Parser.Current_Argument + 1;
365 -- Could it be a file name with wild cards to expand?
369 Arg : constant String :=
370 Argument (Parser, Parser.Current_Argument - 1);
375 while Index <= Arg'Last loop
377 or else Arg (Index) = '?'
378 or else Arg (Index) = '['
380 Parser.In_Expansion := True;
381 Start_Expansion (Parser.Expansion_It, Arg);
382 return Get_Argument (Do_Expansion);
390 return Argument (Parser, Parser.Current_Argument - 1);
393 ----------------------------------
394 -- Find_Longest_Matching_Switch --
395 ----------------------------------
397 procedure Find_Longest_Matching_Switch
400 Index_In_Switches : out Integer;
401 Switch_Length : out Integer;
402 Param : out Switch_Parameter_Type)
405 Length : Natural := 1;
406 P : Switch_Parameter_Type;
409 Index_In_Switches := 0;
412 -- Remove all leading spaces first to make sure that Index points
413 -- at the start of the first switch.
415 Index := Switches'First;
416 while Index <= Switches'Last and then Switches (Index) = ' ' loop
420 while Index <= Switches'Last loop
422 -- Search the length of the parameter at this position in Switches
425 while Length <= Switches'Last
426 and then Switches (Length) /= ' '
428 Length := Length + 1;
431 if Length = Index + 1 then
434 case Switches (Length - 1) is
436 P := Parameter_With_Optional_Space;
437 Length := Length - 1;
439 P := Parameter_With_Space_Or_Equal;
440 Length := Length - 1;
442 P := Parameter_No_Space;
443 Length := Length - 1;
445 P := Parameter_Optional;
446 Length := Length - 1;
452 -- If it is the one we searched, it may be a candidate
454 if Arg'First + Length - 1 - Index <= Arg'Last
455 and then Switches (Index .. Length - 1) =
456 Arg (Arg'First .. Arg'First + Length - 1 - Index)
457 and then Length - Index > Switch_Length
460 Index_In_Switches := Index;
461 Switch_Length := Length - Index;
464 -- Look for the next switch in Switches
466 while Index <= Switches'Last
467 and then Switches (Index) /= ' '
474 end Find_Longest_Matching_Switch;
482 Concatenate : Boolean := True;
483 Parser : Opt_Parser := Command_Line_Parser) return Character
486 pragma Unreferenced (Dummy);
491 -- If we have finished parsing the current command line item (there
492 -- might be multiple switches in a single item), then go to the next
495 if Parser.Current_Argument > Parser.Arg_Count
496 or else (Parser.Current_Index >
497 Argument (Parser, Parser.Current_Argument)'Last
498 and then not Goto_Next_Argument_In_Section (Parser))
503 -- By default, the switch will not have a parameter
505 Parser.The_Parameter :=
506 (Integer'Last, Integer'Last, Integer'Last - 1, ASCII.NUL);
507 Parser.The_Separator := ASCII.NUL;
510 Arg : constant String :=
511 Argument (Parser, Parser.Current_Argument);
512 Index_Switches : Natural := 0;
513 Max_Length : Natural := 0;
515 Param : Switch_Parameter_Type;
517 -- If we are on a new item, test if this might be a switch
519 if Parser.Current_Index = Arg'First then
520 if Arg (Arg'First) /= Parser.Switch_Character then
522 -- If it isn't a switch, return it immediately. We also know it
523 -- isn't the parameter to a previous switch, since that has
524 -- already been handled
526 if Switches (Switches'First) = '*' then
529 Arg_Num => Parser.Current_Argument,
532 Parser.Is_Switch (Parser.Current_Argument) := True;
533 Dummy := Goto_Next_Argument_In_Section (Parser);
537 if Parser.Stop_At_First then
538 Parser.Current_Argument := Positive'Last;
541 elsif not Goto_Next_Argument_In_Section (Parser) then
545 -- Recurse to get the next switch on the command line
551 -- We are on the first character of a new command line argument,
552 -- which starts with Switch_Character. Further analysis is needed.
554 Parser.Current_Index := Parser.Current_Index + 1;
555 Parser.Is_Switch (Parser.Current_Argument) := True;
558 Find_Longest_Matching_Switch
559 (Switches => Switches,
560 Arg => Arg (Parser.Current_Index .. Arg'Last),
561 Index_In_Switches => Index_Switches,
562 Switch_Length => Max_Length,
565 -- If switch is not accepted, it is either invalid or is returned
566 -- in the context of '*'.
568 if Index_Switches = 0 then
570 -- Depending on the value of Concatenate, the full switch is
571 -- a single character or the rest of the argument.
574 End_Index := Parser.Current_Index;
576 End_Index := Arg'Last;
579 if Switches (Switches'First) = '*' then
581 -- Always prepend the switch character, so that users know that
582 -- this comes from a switch on the command line. This is
583 -- especially important when Concatenate is False, since
584 -- otherwise the current argument first character is lost.
588 Arg_Num => Parser.Current_Argument,
589 First => Parser.Current_Index,
591 Extra => Parser.Switch_Character);
592 Parser.Is_Switch (Parser.Current_Argument) := True;
593 Dummy := Goto_Next_Argument_In_Section (Parser);
599 Arg_Num => Parser.Current_Argument,
600 First => Parser.Current_Index,
602 Parser.Current_Index := End_Index + 1;
603 raise Invalid_Switch;
606 End_Index := Parser.Current_Index + Max_Length - 1;
609 Arg_Num => Parser.Current_Argument,
610 First => Parser.Current_Index,
614 when Parameter_With_Optional_Space =>
615 if End_Index < Arg'Last then
617 (Parser.The_Parameter,
618 Arg_Num => Parser.Current_Argument,
619 First => End_Index + 1,
621 Dummy := Goto_Next_Argument_In_Section (Parser);
623 elsif Parser.Current_Argument < Parser.Arg_Count
624 and then Parser.Section (Parser.Current_Argument + 1) /= 0
626 Parser.Current_Argument := Parser.Current_Argument + 1;
627 Parser.The_Separator := ' ';
629 (Parser.The_Parameter,
630 Arg_Num => Parser.Current_Argument,
631 First => Argument (Parser, Parser.Current_Argument)'First,
632 Last => Argument (Parser, Parser.Current_Argument)'Last);
633 Parser.Is_Switch (Parser.Current_Argument) := True;
634 Dummy := Goto_Next_Argument_In_Section (Parser);
637 Parser.Current_Index := End_Index + 1;
638 raise Invalid_Parameter;
641 when Parameter_With_Space_Or_Equal =>
643 -- If the switch is of the form <switch>=xxx
645 if End_Index < Arg'Last then
647 if Arg (End_Index + 1) = '='
648 and then End_Index + 1 < Arg'Last
650 Parser.The_Separator := '=';
652 (Parser.The_Parameter,
653 Arg_Num => Parser.Current_Argument,
654 First => End_Index + 2,
656 Dummy := Goto_Next_Argument_In_Section (Parser);
658 Parser.Current_Index := End_Index + 1;
659 raise Invalid_Parameter;
662 -- If the switch is of the form <switch> xxx
664 elsif Parser.Current_Argument < Parser.Arg_Count
665 and then Parser.Section (Parser.Current_Argument + 1) /= 0
667 Parser.Current_Argument := Parser.Current_Argument + 1;
668 Parser.The_Separator := ' ';
670 (Parser.The_Parameter,
671 Arg_Num => Parser.Current_Argument,
672 First => Argument (Parser, Parser.Current_Argument)'First,
673 Last => Argument (Parser, Parser.Current_Argument)'Last);
674 Parser.Is_Switch (Parser.Current_Argument) := True;
675 Dummy := Goto_Next_Argument_In_Section (Parser);
678 Parser.Current_Index := End_Index + 1;
679 raise Invalid_Parameter;
682 when Parameter_No_Space =>
684 if End_Index < Arg'Last then
686 (Parser.The_Parameter,
687 Arg_Num => Parser.Current_Argument,
688 First => End_Index + 1,
690 Dummy := Goto_Next_Argument_In_Section (Parser);
693 Parser.Current_Index := End_Index + 1;
694 raise Invalid_Parameter;
697 when Parameter_Optional =>
699 if End_Index < Arg'Last then
701 (Parser.The_Parameter,
702 Arg_Num => Parser.Current_Argument,
703 First => End_Index + 1,
707 Dummy := Goto_Next_Argument_In_Section (Parser);
709 when Parameter_None =>
711 if Concatenate or else End_Index = Arg'Last then
712 Parser.Current_Index := End_Index + 1;
715 -- If Concatenate is False and the full argument is not
716 -- recognized as a switch, this is an invalid switch.
718 if Switches (Switches'First) = '*' then
721 Arg_Num => Parser.Current_Argument,
724 Parser.Is_Switch (Parser.Current_Argument) := True;
725 Dummy := Goto_Next_Argument_In_Section (Parser);
731 Arg_Num => Parser.Current_Argument,
732 First => Parser.Current_Index,
734 Parser.Current_Index := Arg'Last + 1;
735 raise Invalid_Switch;
739 return Switches (Index_Switches);
743 -----------------------------------
744 -- Goto_Next_Argument_In_Section --
745 -----------------------------------
747 function Goto_Next_Argument_In_Section
748 (Parser : Opt_Parser) return Boolean
751 Parser.Current_Argument := Parser.Current_Argument + 1;
753 if Parser.Current_Argument > Parser.Arg_Count
754 or else Parser.Section (Parser.Current_Argument) = 0
757 Parser.Current_Argument := Parser.Current_Argument + 1;
759 if Parser.Current_Argument > Parser.Arg_Count then
760 Parser.Current_Index := 1;
764 exit when Parser.Section (Parser.Current_Argument) =
765 Parser.Current_Section;
769 Parser.Current_Index :=
770 Argument (Parser, Parser.Current_Argument)'First;
773 end Goto_Next_Argument_In_Section;
779 procedure Goto_Section
780 (Name : String := "";
781 Parser : Opt_Parser := Command_Line_Parser)
786 Parser.In_Expansion := False;
789 Parser.Current_Argument := 1;
790 Parser.Current_Index := 1;
791 Parser.Current_Section := 1;
796 while Index <= Parser.Arg_Count loop
797 if Parser.Section (Index) = 0
798 and then Argument (Parser, Index) = Parser.Switch_Character & Name
800 Parser.Current_Argument := Index + 1;
801 Parser.Current_Index := 1;
803 if Parser.Current_Argument <= Parser.Arg_Count then
804 Parser.Current_Section :=
805 Parser.Section (Parser.Current_Argument);
813 Parser.Current_Argument := Positive'Last;
814 Parser.Current_Index := 2; -- so that Get_Argument returns nothing
817 ----------------------------
818 -- Initialize_Option_Scan --
819 ----------------------------
821 procedure Initialize_Option_Scan
822 (Switch_Char : Character := '-';
823 Stop_At_First_Non_Switch : Boolean := False;
824 Section_Delimiters : String := "")
827 Internal_Initialize_Option_Scan
828 (Parser => Command_Line_Parser,
829 Switch_Char => Switch_Char,
830 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
831 Section_Delimiters => Section_Delimiters);
832 end Initialize_Option_Scan;
834 ----------------------------
835 -- Initialize_Option_Scan --
836 ----------------------------
838 procedure Initialize_Option_Scan
839 (Parser : out Opt_Parser;
840 Command_Line : GNAT.OS_Lib.Argument_List_Access;
841 Switch_Char : Character := '-';
842 Stop_At_First_Non_Switch : Boolean := False;
843 Section_Delimiters : String := "")
848 if Command_Line = null then
849 Parser := new Opt_Parser_Data (CL.Argument_Count);
850 Initialize_Option_Scan
851 (Switch_Char => Switch_Char,
852 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
853 Section_Delimiters => Section_Delimiters);
855 Parser := new Opt_Parser_Data (Command_Line'Length);
856 Parser.Arguments := Command_Line;
857 Internal_Initialize_Option_Scan
859 Switch_Char => Switch_Char,
860 Stop_At_First_Non_Switch => Stop_At_First_Non_Switch,
861 Section_Delimiters => Section_Delimiters);
863 end Initialize_Option_Scan;
865 -------------------------------------
866 -- Internal_Initialize_Option_Scan --
867 -------------------------------------
869 procedure Internal_Initialize_Option_Scan
870 (Parser : Opt_Parser;
871 Switch_Char : Character;
872 Stop_At_First_Non_Switch : Boolean;
873 Section_Delimiters : String)
875 Section_Num : Section_Number;
876 Section_Index : Integer;
878 Delimiter_Found : Boolean;
881 pragma Warnings (Off, Discard);
884 Parser.Current_Argument := 0;
885 Parser.Current_Index := 0;
886 Parser.In_Expansion := False;
887 Parser.Switch_Character := Switch_Char;
888 Parser.Stop_At_First := Stop_At_First_Non_Switch;
890 -- If we are using sections, we have to preprocess the command line
891 -- to delimit them. A section can be repeated, so we just give each
892 -- item on the command line a section number
895 Section_Index := Section_Delimiters'First;
896 while Section_Index <= Section_Delimiters'Last loop
897 Last := Section_Index;
898 while Last <= Section_Delimiters'Last
899 and then Section_Delimiters (Last) /= ' '
904 Delimiter_Found := False;
905 Section_Num := Section_Num + 1;
907 for Index in 1 .. Parser.Arg_Count loop
908 if Argument (Parser, Index)(1) = Parser.Switch_Character
910 Argument (Parser, Index) = Parser.Switch_Character &
912 (Section_Index .. Last - 1)
914 Parser.Section (Index) := 0;
915 Delimiter_Found := True;
917 elsif Parser.Section (Index) = 0 then
918 Delimiter_Found := False;
920 elsif Delimiter_Found then
921 Parser.Section (Index) := Section_Num;
925 Section_Index := Last + 1;
926 while Section_Index <= Section_Delimiters'Last
927 and then Section_Delimiters (Section_Index) = ' '
929 Section_Index := Section_Index + 1;
933 Discard := Goto_Next_Argument_In_Section (Parser);
934 end Internal_Initialize_Option_Scan;
941 (Parser : Opt_Parser := Command_Line_Parser) return String
944 if Parser.The_Parameter.First > Parser.The_Parameter.Last then
945 return String'(1 .. 0 => ' ');
947 return Argument (Parser, Parser.The_Parameter.Arg_Num)
948 (Parser.The_Parameter.First .. Parser.The_Parameter.Last);
957 (Parser : Opt_Parser := Command_Line_Parser) return Character
960 return Parser.The_Separator;
967 procedure Set_Parameter
968 (Variable : out Parameter_Type;
972 Extra : Character := ASCII.NUL)
975 Variable.Arg_Num := Arg_Num;
976 Variable.First := First;
977 Variable.Last := Last;
978 Variable.Extra := Extra;
981 ---------------------
982 -- Start_Expansion --
983 ---------------------
985 procedure Start_Expansion
986 (Iterator : out Expansion_Iterator;
988 Directory : String := "";
989 Basic_Regexp : Boolean := True)
991 Directory_Separator : Character;
992 pragma Import (C, Directory_Separator, "__gnat_dir_separator");
994 First : Positive := Pattern'First;
995 Pat : String := Pattern;
998 Canonical_Case_File_Name (Pat);
999 Iterator.Current_Depth := 1;
1001 -- If Directory is unspecified, use the current directory ("./" or ".\")
1003 if Directory = "" then
1004 Iterator.Dir_Name (1 .. 2) := "." & Directory_Separator;
1005 Iterator.Start := 3;
1008 Iterator.Dir_Name (1 .. Directory'Length) := Directory;
1009 Iterator.Start := Directory'Length + 1;
1010 Canonical_Case_File_Name (Iterator.Dir_Name (1 .. Directory'Length));
1012 -- Make sure that the last character is a directory separator
1014 if Directory (Directory'Last) /= Directory_Separator then
1015 Iterator.Dir_Name (Iterator.Start) := Directory_Separator;
1016 Iterator.Start := Iterator.Start + 1;
1020 Iterator.Levels (1).Name_Last := Iterator.Start - 1;
1022 -- Open the initial Directory, at depth 1
1024 GNAT.Directory_Operations.Open
1025 (Iterator.Levels (1).Dir, Iterator.Dir_Name (1 .. Iterator.Start - 1));
1027 -- If in the current directory and the pattern starts with "./" or ".\",
1028 -- drop the "./" or ".\" from the pattern.
1030 if Directory = "" and then Pat'Length > 2
1031 and then Pat (Pat'First) = '.'
1032 and then Pat (Pat'First + 1) = Directory_Separator
1034 First := Pat'First + 2;
1038 GNAT.Regexp.Compile (Pat (First .. Pat'Last), Basic_Regexp, True);
1040 Iterator.Maximum_Depth := 1;
1042 -- Maximum_Depth is equal to 1 plus the number of directory separators
1045 for Index in First .. Pat'Last loop
1046 if Pat (Index) = Directory_Separator then
1047 Iterator.Maximum_Depth := Iterator.Maximum_Depth + 1;
1048 exit when Iterator.Maximum_Depth = Max_Depth;
1051 end Start_Expansion;
1057 procedure Free (Parser : in out Opt_Parser) is
1058 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1059 (Opt_Parser_Data, Opt_Parser);
1062 and then Parser /= Command_Line_Parser
1064 Free (Parser.Arguments);
1065 Unchecked_Free (Parser);
1073 procedure Define_Alias
1074 (Config : in out Command_Line_Configuration;
1079 if Config = null then
1080 Config := new Command_Line_Configuration_Record;
1083 Append (Config.Aliases, new String'(Switch));
1084 Append (Config.Expansions, new String'(Expanded));
1091 procedure Define_Prefix
1092 (Config : in out Command_Line_Configuration;
1096 if Config = null then
1097 Config := new Command_Line_Configuration_Record;
1100 Append (Config.Prefixes, new String'(Prefix));
1107 procedure Define_Switch
1108 (Config : in out Command_Line_Configuration;
1112 if Config = null then
1113 Config := new Command_Line_Configuration_Record;
1116 Append (Config.Switches, new String'(Switch));
1119 --------------------
1120 -- Define_Section --
1121 --------------------
1123 procedure Define_Section
1124 (Config : in out Command_Line_Configuration;
1128 if Config = null then
1129 Config := new Command_Line_Configuration_Record;
1132 Append (Config.Sections, new String'(Section));
1139 function Get_Switches
1140 (Config : Command_Line_Configuration;
1141 Switch_Char : Character)
1144 Ret : Ada.Strings.Unbounded.Unbounded_String;
1145 use type Ada.Strings.Unbounded.Unbounded_String;
1147 if Config = null or else Config.Switches = null then
1151 for J in Config.Switches'Range loop
1152 if Config.Switches (J) (Config.Switches (J)'First) = Switch_Char then
1155 (Config.Switches (J)'First + 1 .. Config.Switches (J)'Last);
1157 Ret := Ret & " " & Config.Switches (J).all;
1161 return Ada.Strings.Unbounded.To_String (Ret);
1164 -----------------------
1165 -- Set_Configuration --
1166 -----------------------
1168 procedure Set_Configuration
1169 (Cmd : in out Command_Line;
1170 Config : Command_Line_Configuration)
1173 Cmd.Config := Config;
1174 end Set_Configuration;
1176 -----------------------
1177 -- Get_Configuration --
1178 -----------------------
1180 function Get_Configuration
1181 (Cmd : Command_Line) return Command_Line_Configuration is
1184 end Get_Configuration;
1186 ----------------------
1187 -- Set_Command_Line --
1188 ----------------------
1190 procedure Set_Command_Line
1191 (Cmd : in out Command_Line;
1193 Getopt_Description : String := "";
1194 Switch_Char : Character := '-')
1196 Tmp : Argument_List_Access;
1197 Parser : Opt_Parser;
1199 Section : String_Access := null;
1201 function Real_Full_Switch
1203 Parser : Opt_Parser) return String;
1204 -- Ensure that the returned switch value contains the
1205 -- Switch_Char prefix if needed.
1207 ----------------------
1208 -- Real_Full_Switch --
1209 ----------------------
1211 function Real_Full_Switch
1213 Parser : Opt_Parser) return String
1217 return Full_Switch (Parser);
1219 return Switch_Char & Full_Switch (Parser);
1221 end Real_Full_Switch;
1223 -- Start of processing for Set_Command_Line
1226 Free (Cmd.Expanded);
1229 if Switches /= "" then
1230 Tmp := Argument_String_To_List (Switches);
1231 Initialize_Option_Scan (Parser, Tmp, Switch_Char);
1235 S := Getopt (Switches => "* " & Getopt_Description,
1236 Concatenate => False,
1238 exit when S = ASCII.NUL;
1241 Sw : constant String :=
1242 Real_Full_Switch (S, Parser);
1243 Is_Section : Boolean := False;
1246 if Cmd.Config /= null
1247 and then Cmd.Config.Sections /= null
1250 for S in Cmd.Config.Sections'Range loop
1251 if Sw = Cmd.Config.Sections (S).all then
1252 Section := Cmd.Config.Sections (S);
1255 exit Section_Search;
1257 end loop Section_Search;
1260 if not Is_Section then
1261 if Section = null then
1262 -- Workaround some weird cases: some switches may
1263 -- expect parameters, but have the same value as
1264 -- longer switches: -gnaty3 (-gnaty, parameter=3) and
1265 -- -gnatya (-gnatya, no parameter).
1266 -- So we are calling add_switch here with parameter
1267 -- attached. This will be anyway correctly handled by
1268 -- Add_Switch if -gnaty3 is actually furnished.
1269 if Separator (Parser) = ASCII.NUL then
1271 (Cmd, Sw & Parameter (Parser), "");
1274 (Cmd, Sw, Parameter (Parser), Separator (Parser));
1277 if Separator (Parser) = ASCII.NUL then
1279 (Cmd, Sw & Parameter (Parser), "",
1294 when Invalid_Parameter =>
1296 -- Add it with no parameter, if that's the way the user
1298 -- Specify the separator in all cases, as the switch might
1299 -- need to be unaliased, and the alias might contain
1300 -- switches with parameters.
1302 if Section = null then
1304 (Cmd, Switch_Char & Full_Switch (Parser),
1305 Separator => Separator (Parser));
1308 (Cmd, Switch_Char & Full_Switch (Parser),
1309 Separator => Separator (Parser),
1310 Section => Section.all);
1317 end Set_Command_Line;
1326 Substring : String) return Boolean is
1328 return Index + Substring'Length - 1 <= Type_Str'Last
1329 and then Type_Str (Index .. Index + Substring'Length - 1) = Substring;
1332 ------------------------
1333 -- Can_Have_Parameter --
1334 ------------------------
1336 function Can_Have_Parameter (S : String) return Boolean is
1338 if S'Length <= 1 then
1343 when '!' | ':' | '?' | '=' =>
1348 end Can_Have_Parameter;
1350 -----------------------
1351 -- Require_Parameter --
1352 -----------------------
1354 function Require_Parameter (S : String) return Boolean is
1356 if S'Length <= 1 then
1361 when '!' | ':' | '=' =>
1366 end Require_Parameter;
1372 function Actual_Switch (S : String) return String is
1374 if S'Length <= 1 then
1379 when '!' | ':' | '?' | '=' =>
1380 return S (S'First .. S'Last - 1);
1386 ----------------------------
1387 -- For_Each_Simple_Switch --
1388 ----------------------------
1390 procedure For_Each_Simple_Switch
1391 (Cmd : Command_Line;
1393 Parameter : String := "";
1394 Unalias : Boolean := True)
1396 function Group_Analysis
1398 Group : String) return Boolean;
1399 -- Perform the analysis of a group of switches.
1401 --------------------
1402 -- Group_Analysis --
1403 --------------------
1405 function Group_Analysis
1407 Group : String) return Boolean
1409 Idx : Natural := Group'First;
1412 while Idx <= Group'Last loop
1415 for S in Cmd.Config.Switches'Range loop
1417 Sw : constant String :=
1419 (Cmd.Config.Switches (S).all);
1420 Full : constant String :=
1421 Prefix & Group (Idx .. Group'Last);
1426 if Sw'Length >= Prefix'Length
1427 -- Verify that sw starts with Prefix
1428 and then Looking_At (Sw, Sw'First, Prefix)
1429 -- Verify that the group starts with sw
1430 and then Looking_At (Full, Full'First, Sw)
1432 Last := Idx + Sw'Length - Prefix'Length - 1;
1435 if Can_Have_Parameter (Cmd.Config.Switches (S).all) then
1436 -- Include potential parameter to the recursive call.
1437 -- Only numbers are allowed.
1438 while Last < Group'Last
1439 and then Group (Last + 1) in '0' .. '9'
1445 if not Require_Parameter (Cmd.Config.Switches (S).all)
1446 or else Last >= Param
1448 if Idx = Group'First
1449 and then Last = Group'Last
1450 and then Last < Param
1452 -- The group only concerns a single switch. Do not
1453 -- perform recursive call.
1455 -- Note that we still perform a recursive call if
1456 -- a parameter is detected in the switch, as this
1457 -- is a way to correctly identify such a parameter
1464 -- Recursive call, using the detected parameter if any
1465 if Last >= Param then
1466 For_Each_Simple_Switch
1468 Prefix & Group (Idx .. Param - 1),
1469 Group (Param .. Last));
1471 For_Each_Simple_Switch
1472 (Cmd, Prefix & Group (Idx .. Last), "");
1483 For_Each_Simple_Switch (Cmd, Prefix & Group (Idx), "");
1492 -- Are we adding a switch that can in fact be expanded through aliases ?
1493 -- If yes, we add separately each of its expansion.
1495 -- This takes care of expansions like "-T" -> "-gnatwrs", where the
1496 -- alias and its expansion do not have the same prefix. Given the order
1497 -- in which we do things here, the expansion of the alias will itself
1498 -- be checked for a common prefix and further split into simple switches
1501 and then Cmd.Config /= null
1502 and then Cmd.Config.Aliases /= null
1504 for A in Cmd.Config.Aliases'Range loop
1505 if Cmd.Config.Aliases (A).all = Switch
1506 and then Parameter = ""
1508 For_Each_Simple_Switch
1509 (Cmd, Cmd.Config.Expansions (A).all, "");
1515 -- Are we adding a switch grouping several switches ? If yes, add each
1516 -- of the simple switches instead.
1518 if Cmd.Config /= null
1519 and then Cmd.Config.Prefixes /= null
1521 for P in Cmd.Config.Prefixes'Range loop
1522 if Switch'Length > Cmd.Config.Prefixes (P)'Length + 1
1524 (Switch, Switch'First, Cmd.Config.Prefixes (P).all)
1526 -- Alias expansion will be done recursively
1527 if Cmd.Config.Switches = null then
1528 for S in Switch'First + Cmd.Config.Prefixes (P)'Length
1531 For_Each_Simple_Switch
1532 (Cmd, Cmd.Config.Prefixes (P).all & Switch (S), "");
1537 elsif Group_Analysis
1538 (Cmd.Config.Prefixes (P).all,
1540 (Switch'First + Cmd.Config.Prefixes (P)'Length
1543 -- Recursive calls already done on each switch of the
1544 -- group. Let's return to not call Callback.
1551 Callback (Switch, Parameter);
1552 end For_Each_Simple_Switch;
1558 procedure Add_Switch
1559 (Cmd : in out Command_Line;
1561 Parameter : String := "";
1562 Separator : Character := ' ';
1563 Section : String := "")
1566 pragma Unreferenced (Success);
1568 Add_Switch (Cmd, Switch, Parameter, Separator, Section, Success);
1575 procedure Add_Switch
1576 (Cmd : in out Command_Line;
1578 Parameter : String := "";
1579 Separator : Character := ' ';
1580 Section : String := "";
1581 Success : out Boolean)
1583 procedure Add_Simple_Switch (Simple : String; Param : String);
1584 -- Add a new switch that has had all its aliases expanded, and switches
1585 -- ungrouped. We know there is no more aliases in Switches
1587 -----------------------
1588 -- Add_Simple_Switch --
1589 -----------------------
1591 procedure Add_Simple_Switch (Simple : String; Param : String) is
1593 if Cmd.Expanded = null then
1594 Cmd.Expanded := new Argument_List'(1 .. 1 => new String'(Simple));
1597 Cmd.Params := new Argument_List'
1598 (1 .. 1 => new String'(Separator & Param));
1601 Cmd.Params := new Argument_List'(1 .. 1 => null);
1604 if Section = "" then
1605 Cmd.Sections := new Argument_List'(1 .. 1 => null);
1608 Cmd.Sections := new Argument_List'
1609 (1 .. 1 => new String'(Section));
1613 -- Do we already have this switch ?
1615 for C in Cmd.Expanded'Range loop
1616 if Cmd.Expanded (C).all = Simple
1618 ((Cmd.Params (C) = null and then Param = "")
1620 (Cmd.Params (C) /= null
1621 and then Cmd.Params (C).all = Separator & Param))
1623 ((Cmd.Sections (C) = null and then Section = "")
1625 (Cmd.Sections (C) /= null
1626 and then Cmd.Sections (C).all = Section))
1632 -- Inserting at least one switch
1634 Append (Cmd.Expanded, new String'(Simple));
1637 Append (Cmd.Params, new String'(Separator & Param));
1640 Append (Cmd.Params, null);
1643 if Section = "" then
1644 Append (Cmd.Sections, null);
1646 Append (Cmd.Sections, new String'(Section));
1649 end Add_Simple_Switch;
1651 procedure Add_Simple_Switches is
1652 new For_Each_Simple_Switch (Add_Simple_Switch);
1654 -- Start of processing for Add_Switch
1658 Add_Simple_Switches (Cmd, Switch, Parameter);
1659 Free (Cmd.Coalesce);
1666 procedure Remove (Line : in out Argument_List_Access; Index : Integer) is
1667 Tmp : Argument_List_Access := Line;
1670 Line := new Argument_List (Tmp'First .. Tmp'Last - 1);
1672 if Index /= Tmp'First then
1673 Line (Tmp'First .. Index - 1) := Tmp (Tmp'First .. Index - 1);
1678 if Index /= Tmp'Last then
1679 Line (Index .. Tmp'Last - 1) := Tmp (Index + 1 .. Tmp'Last);
1682 Unchecked_Free (Tmp);
1690 (Line : in out Argument_List_Access;
1691 Str : String_Access)
1693 Tmp : Argument_List_Access := Line;
1696 Line := new Argument_List (Tmp'First .. Tmp'Last + 1);
1697 Line (Tmp'Range) := Tmp.all;
1698 Unchecked_Free (Tmp);
1700 Line := new Argument_List (1 .. 1);
1703 Line (Line'Last) := Str;
1710 procedure Remove_Switch
1711 (Cmd : in out Command_Line;
1713 Remove_All : Boolean := False;
1714 Has_Parameter : Boolean := False;
1715 Section : String := "")
1718 pragma Unreferenced (Success);
1720 Remove_Switch (Cmd, Switch, Remove_All, Has_Parameter, Section, Success);
1727 procedure Remove_Switch
1728 (Cmd : in out Command_Line;
1730 Remove_All : Boolean := False;
1731 Has_Parameter : Boolean := False;
1732 Section : String := "";
1733 Success : out Boolean)
1735 procedure Remove_Simple_Switch (Simple : String; Param : String);
1736 -- Removes a simple switch, with no aliasing or grouping
1738 --------------------------
1739 -- Remove_Simple_Switch --
1740 --------------------------
1742 procedure Remove_Simple_Switch (Simple : String; Param : String) is
1744 pragma Unreferenced (Param);
1747 if Cmd.Expanded /= null then
1748 C := Cmd.Expanded'First;
1749 while C <= Cmd.Expanded'Last loop
1750 if Cmd.Expanded (C).all = Simple
1753 or else (Cmd.Sections (C) = null
1754 and then Section = "")
1755 or else (Cmd.Sections (C) /= null
1756 and then Section = Cmd.Sections (C).all))
1757 and then (not Has_Parameter or else Cmd.Params (C) /= null)
1759 Remove (Cmd.Expanded, C);
1760 Remove (Cmd.Params, C);
1761 Remove (Cmd.Sections, C);
1764 if not Remove_All then
1773 end Remove_Simple_Switch;
1775 procedure Remove_Simple_Switches is
1776 new For_Each_Simple_Switch (Remove_Simple_Switch);
1778 -- Start of processing for Remove_Switch
1782 Remove_Simple_Switches (Cmd, Switch, "", Unalias => not Has_Parameter);
1783 Free (Cmd.Coalesce);
1790 procedure Remove_Switch
1791 (Cmd : in out Command_Line;
1794 Section : String := "")
1796 procedure Remove_Simple_Switch (Simple : String; Param : String);
1797 -- Removes a simple switch, with no aliasing or grouping
1799 --------------------------
1800 -- Remove_Simple_Switch --
1801 --------------------------
1803 procedure Remove_Simple_Switch (Simple : String; Param : String) is
1807 if Cmd.Expanded /= null then
1808 C := Cmd.Expanded'First;
1809 while C <= Cmd.Expanded'Last loop
1810 if Cmd.Expanded (C).all = Simple
1812 ((Cmd.Sections (C) = null
1813 and then Section = "")
1815 (Cmd.Sections (C) /= null
1816 and then Section = Cmd.Sections (C).all))
1818 ((Cmd.Params (C) = null and then Param = "")
1820 (Cmd.Params (C) /= null
1823 -- Ignore the separator stored in Parameter
1825 Cmd.Params (C) (Cmd.Params (C)'First + 1
1826 .. Cmd.Params (C)'Last) =
1829 Remove (Cmd.Expanded, C);
1830 Remove (Cmd.Params, C);
1831 Remove (Cmd.Sections, C);
1833 -- The switch is necessarily unique by construction of
1843 end Remove_Simple_Switch;
1845 procedure Remove_Simple_Switches is
1846 new For_Each_Simple_Switch (Remove_Simple_Switch);
1848 -- Start of processing for Remove_Switch
1851 Remove_Simple_Switches (Cmd, Switch, Parameter);
1852 Free (Cmd.Coalesce);
1855 --------------------
1856 -- Group_Switches --
1857 --------------------
1859 procedure Group_Switches
1860 (Cmd : Command_Line;
1861 Result : Argument_List_Access;
1862 Sections : Argument_List_Access;
1863 Params : Argument_List_Access)
1865 function Compatible_Parameter (Param : String_Access) return Boolean;
1866 -- Tell if the parameter can be part of a group
1868 --------------------------
1869 -- Compatible_Parameter --
1870 --------------------------
1872 function Compatible_Parameter (Param : String_Access) return Boolean is
1874 if Param = null then
1878 elsif Param (Param'First) /= ASCII.NUL then
1879 -- We need parameters without separators...
1883 -- We need number only parameters.
1884 for J in Param'First + 1 .. Param'Last loop
1885 if Param (J) not in '0' .. '9' then
1893 end Compatible_Parameter;
1895 Group : Ada.Strings.Unbounded.Unbounded_String;
1897 use type Ada.Strings.Unbounded.Unbounded_String;
1900 if Cmd.Config = null
1901 or else Cmd.Config.Prefixes = null
1906 for P in Cmd.Config.Prefixes'Range loop
1907 Group := Ada.Strings.Unbounded.Null_Unbounded_String;
1910 for C in Result'Range loop
1911 if Result (C) /= null
1912 and then Compatible_Parameter (Params (C))
1914 (Result (C).all, Result (C)'First, Cmd.Config.Prefixes (P).all)
1916 -- If we are still in the same section, group the switches
1919 (Sections (C) = null
1920 and then Sections (First) = null)
1922 (Sections (C) /= null
1923 and then Sections (First) /= null
1924 and then Sections (C).all = Sections (First).all)
1929 (Result (C)'First + Cmd.Config.Prefixes (P)'Length ..
1932 if Params (C) /= null then
1934 Params (C) (Params (C)'First + 1 .. Params (C)'Last);
1944 -- We changed section: we put the grouped switches to the
1945 -- first place, on continue with the new section.
1948 (Cmd.Config.Prefixes (P).all &
1949 Ada.Strings.Unbounded.To_String (Group));
1951 Ada.Strings.Unbounded.To_Unbounded_String
1953 (Result (C)'First + Cmd.Config.Prefixes (P)'Length ..
1963 (Cmd.Config.Prefixes (P).all &
1964 Ada.Strings.Unbounded.To_String (Group));
1969 --------------------
1970 -- Alias_Switches --
1971 --------------------
1973 procedure Alias_Switches
1974 (Cmd : Command_Line;
1975 Result : Argument_List_Access;
1976 Params : Argument_List_Access)
1981 procedure Check_Cb (Switch : String; Param : String);
1982 -- Comment required ???
1984 procedure Remove_Cb (Switch : String; Param : String);
1985 -- Comment required ???
1991 procedure Check_Cb (Switch : String; Param : String) is
1994 for E in Result'Range loop
1995 if Result (E) /= null
1998 or else Params (E) (Params (E)'First + 1
1999 .. Params (E)'Last) = Param)
2000 and then Result (E).all = Switch
2014 procedure Remove_Cb (Switch : String; Param : String) is
2016 for E in Result'Range loop
2017 if Result (E) /= null
2020 or else Params (E) (Params (E)'First + 1
2021 .. Params (E)'Last) = Param)
2022 and then Result (E).all = Switch
2034 procedure Check_All is new For_Each_Simple_Switch (Check_Cb);
2035 procedure Remove_All is new For_Each_Simple_Switch (Remove_Cb);
2037 -- Start of processing for Alias_Switches
2040 if Cmd.Config = null
2041 or else Cmd.Config.Aliases = null
2046 for A in Cmd.Config.Aliases'Range loop
2048 -- Compute the various simple switches that make up the alias. We
2049 -- split the expansion into as many simple switches as possible, and
2050 -- then check whether the expanded command line has all of them.
2053 Check_All (Cmd, Cmd.Config.Expansions (A).all);
2056 First := Integer'Last;
2057 Remove_All (Cmd, Cmd.Config.Expansions (A).all);
2058 Result (First) := new String'(Cmd.Config.Aliases (A).all);
2067 procedure Sort_Sections
2068 (Line : GNAT.OS_Lib.Argument_List_Access;
2069 Sections : GNAT.OS_Lib.Argument_List_Access;
2070 Params : GNAT.OS_Lib.Argument_List_Access)
2072 Sections_List : Argument_List_Access :=
2073 new Argument_List'(1 .. 1 => null);
2075 Old_Line : constant Argument_List := Line.all;
2076 Old_Sections : constant Argument_List := Sections.all;
2077 Old_Params : constant Argument_List := Params.all;
2085 -- First construct a list of all sections
2087 for E in Line'Range loop
2088 if Sections (E) /= null then
2090 for S in Sections_List'Range loop
2091 if (Sections_List (S) = null and then Sections (E) = null)
2093 (Sections_List (S) /= null
2094 and then Sections (E) /= null
2095 and then Sections_List (S).all = Sections (E).all)
2103 Append (Sections_List, Sections (E));
2108 Index := Line'First;
2110 for S in Sections_List'Range loop
2111 for E in Old_Line'Range loop
2112 if (Sections_List (S) = null and then Old_Sections (E) = null)
2114 (Sections_List (S) /= null
2115 and then Old_Sections (E) /= null
2116 and then Sections_List (S).all = Old_Sections (E).all)
2118 Line (Index) := Old_Line (E);
2119 Sections (Index) := Old_Sections (E);
2120 Params (Index) := Old_Params (E);
2132 (Cmd : in out Command_Line;
2133 Iter : in out Command_Line_Iterator;
2137 if Cmd.Expanded = null then
2142 -- Reorder the expanded line so that sections are grouped
2144 Sort_Sections (Cmd.Expanded, Cmd.Sections, Cmd.Params);
2146 -- Coalesce the switches as much as possible
2149 and then Cmd.Coalesce = null
2151 Cmd.Coalesce := new Argument_List (Cmd.Expanded'Range);
2152 for E in Cmd.Expanded'Range loop
2153 Cmd.Coalesce (E) := new String'(Cmd.Expanded (E).all);
2156 Cmd.Coalesce_Sections := new Argument_List (Cmd.Sections'Range);
2157 for E in Cmd.Sections'Range loop
2158 if Cmd.Sections (E) = null then
2159 Cmd.Coalesce_Sections (E) := null;
2161 Cmd.Coalesce_Sections (E) := new String'(Cmd.Sections (E).all);
2165 Cmd.Coalesce_Params := new Argument_List (Cmd.Params'Range);
2166 for E in Cmd.Params'Range loop
2167 if Cmd.Params (E) = null then
2168 Cmd.Coalesce_Params (E) := null;
2170 Cmd.Coalesce_Params (E) := new String'(Cmd.Params (E).all);
2174 -- Not a clone, since we will not modify the parameters anyway
2176 Alias_Switches (Cmd, Cmd.Coalesce, Cmd.Coalesce_Params);
2178 (Cmd, Cmd.Coalesce, Cmd.Coalesce_Sections, Cmd.Coalesce_Params);
2182 Iter.List := Cmd.Expanded;
2183 Iter.Params := Cmd.Params;
2184 Iter.Sections := Cmd.Sections;
2186 Iter.List := Cmd.Coalesce;
2187 Iter.Params := Cmd.Coalesce_Params;
2188 Iter.Sections := Cmd.Coalesce_Sections;
2191 if Iter.List = null then
2192 Iter.Current := Integer'Last;
2194 Iter.Current := Iter.List'First;
2196 while Iter.Current <= Iter.List'Last
2197 and then Iter.List (Iter.Current) = null
2199 Iter.Current := Iter.Current + 1;
2204 --------------------
2205 -- Current_Switch --
2206 --------------------
2208 function Current_Switch (Iter : Command_Line_Iterator) return String is
2210 return Iter.List (Iter.Current).all;
2213 --------------------
2214 -- Is_New_Section --
2215 --------------------
2217 function Is_New_Section (Iter : Command_Line_Iterator) return Boolean is
2218 Section : constant String := Current_Section (Iter);
2220 if Iter.Sections = null then
2222 elsif Iter.Current = Iter.Sections'First
2223 or else Iter.Sections (Iter.Current - 1) = null
2225 return Section /= "";
2228 return Section /= Iter.Sections (Iter.Current - 1).all;
2231 ---------------------
2232 -- Current_Section --
2233 ---------------------
2235 function Current_Section (Iter : Command_Line_Iterator) return String is
2237 if Iter.Sections = null
2238 or else Iter.Current > Iter.Sections'Last
2239 or else Iter.Sections (Iter.Current) = null
2244 return Iter.Sections (Iter.Current).all;
2245 end Current_Section;
2247 -----------------------
2248 -- Current_Separator --
2249 -----------------------
2251 function Current_Separator (Iter : Command_Line_Iterator) return String is
2253 if Iter.Params = null
2254 or else Iter.Current > Iter.Params'Last
2255 or else Iter.Params (Iter.Current) = null
2261 Sep : constant Character :=
2262 Iter.Params (Iter.Current) (Iter.Params (Iter.Current)'First);
2264 if Sep = ASCII.NUL then
2271 end Current_Separator;
2273 -----------------------
2274 -- Current_Parameter --
2275 -----------------------
2277 function Current_Parameter (Iter : Command_Line_Iterator) return String is
2279 if Iter.Params = null
2280 or else Iter.Current > Iter.Params'Last
2281 or else Iter.Params (Iter.Current) = null
2287 P : constant String := Iter.Params (Iter.Current).all;
2292 return P (P'First + 1 .. P'Last);
2295 end Current_Parameter;
2301 function Has_More (Iter : Command_Line_Iterator) return Boolean is
2303 return Iter.List /= null and then Iter.Current <= Iter.List'Last;
2310 procedure Next (Iter : in out Command_Line_Iterator) is
2312 Iter.Current := Iter.Current + 1;
2313 while Iter.Current <= Iter.List'Last
2314 and then Iter.List (Iter.Current) = null
2316 Iter.Current := Iter.Current + 1;
2324 procedure Free (Config : in out Command_Line_Configuration) is
2326 if Config /= null then
2327 Free (Config.Aliases);
2328 Free (Config.Expansions);
2329 Free (Config.Prefixes);
2330 Unchecked_Free (Config);
2338 procedure Free (Cmd : in out Command_Line) is
2340 Free (Cmd.Expanded);
2341 Free (Cmd.Coalesce);
2345 end GNAT.Command_Line;