diff mbox

[Ada] Set_Command_Line: improve handling of grouped switches with parameters

Message ID 20110803152811.GA3836@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Aug. 3, 2011, 3:28 p.m. UTC
The following code should find two switches on the command line: -gnatyL (with
 parameter "1") and -gnatya. Instead, we used to find a single switch -gnatyL
 with parameter "1a".

   Define_Switch (Config, "-gnatyL!");
   Define_Switch (Config, "-gnatya");
   Define_Prefix (Config, "-gnaty");

   Set_Configuration (Cmd, Config);

   set_Command_Line (Cmd, "-gnatyL1a");
   Start (Cmd, Iter, Expanded => True);
   while Has_More (Iter) loop
      Put_Line (Current_Switch (Iter));
      Next (Iter);
   end loop;

Tested on x86_64-pc-linux-gnu, committed on trunk

2011-08-03  Emmanuel Briot  <briot@adacore.com>

	* g-comlin.adb, g-comlin.ads (Set_Command_Line): ignore the parameter
	Getopt_Switches when we have already define a command line
	configuration.
diff mbox

Patch

Index: g-comlin.adb
===================================================================
--- g-comlin.adb	(revision 177274)
+++ g-comlin.adb	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1999-2010, Free Software Foundation, Inc.         --
+--          Copyright (C) 1999-2011, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -19,10 +19,10 @@ 
 -- additional permissions described in the GCC Runtime Library Exception,   --
 -- version 3.1, as published by the Free Software Foundation.               --
 --                                                                          --
--- You should have received a copy of the GNU General Public License and    --
--- a copy of the GCC Runtime Library Exception along with this program;     --
--- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
--- <http://www.gnu.org/licenses/>.                                          --
+-- In particular,  you can freely  distribute your programs  built with the --
+-- GNAT Pro compiler, including any required library run-time units,  using --
+-- any licensing terms  of your choosing.  See the AdaCore Software License --
+-- for full details.                                                        --
 --                                                                          --
 -- GNAT was originally developed  by the GNAT team at  New York University. --
 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
@@ -200,7 +200,8 @@ 
      (Config   : Command_Line_Configuration;
       Section  : String);
    --  Iterate over all switches defined in Config, for a specific section.
-   --  Index is set to the index in Config.Switches
+   --  Index is set to the index in Config.Switches.
+   --  Stop iterating when Callback returns False.
 
    --------------
    -- Argument --
@@ -1238,6 +1239,10 @@ 
          Unchecked_Free (Tmp);
       end if;
 
+      if Switch.Switch /= null and then Switch.Switch.all = "*" then
+         Config.Star_Switch := True;
+      end if;
+
       Config.Switches (Config.Switches'Last) := Switch;
    end Add;
 
@@ -1592,9 +1597,28 @@ 
 
          loop
             begin
-               S := Getopt (Switches    => "* " & Getopt_Description,
-                            Concatenate => False,
-                            Parser      => Parser);
+               if Cmd.Config /= null then
+                  --  Do not use Getopt_Description in this case. Otherwise,
+                  --  if we have defined a prefix -gnaty, and two switches
+                  --  -gnatya and -gnatyL!, we would have a different behavior
+                  --  depending on the order of switches:
+                  --      -gnatyL1a   =>  -gnatyL with argument "1a"
+                  --      -gnatyaL1   =>  -gnatya and -gnatyL with argument "1"
+                  --  This is because the call to Getopt below knows nothing
+                  --  about prefixes, and in the first case finds a valid
+                  --  switch with arguments, so returns it without analyzing
+                  --  the argument. In the second case, the switch matches "*",
+                  --  and is then decomposed below.
+
+                  S := Getopt (Switches    => "*",
+                               Concatenate => False,
+                               Parser      => Parser);
+               else
+                  S := Getopt (Switches    => "* " & Getopt_Description,
+                               Concatenate => False,
+                               Parser      => Parser);
+               end if;
+
                exit when S = ASCII.NUL;
 
                declare
@@ -1761,6 +1785,8 @@ 
 
          function Analyze_Simple_Switch
            (Switch : String; Index : Integer) return Boolean;
+         --  "Switches" is one of the switch definitions passed to the
+         --  configuration, not one of the switches found on the command line.
 
          ---------------------------
          -- Analyze_Simple_Switch --
@@ -1772,26 +1798,26 @@ 
             pragma Unreferenced (Index);
 
             Full  : constant String := Prefix & Group (Idx .. Group'Last);
+
             Sw    : constant String := Actual_Switch (Switch);
+            --  Switches definition minus argument definition
+
             Last  : Natural;
             Param : Natural;
 
          begin
-            if Sw'Length >= Prefix'Length
+            if
+               --  Verify that sw starts with Prefix
+               Looking_At (Sw, Sw'First, Prefix)
 
-            --  Verify that sw starts with Prefix
+               --  Verify that the group starts with sw
+              and then Looking_At (Full, Full'First, Sw)
 
-              and then Looking_At (Sw, Sw'First, Prefix)
-
-            --  Verify that the group starts with sw
-
-              and then Looking_At (Full, Full'First, Sw)
             then
                Last  := Idx + Sw'Length - Prefix'Length - 1;
                Param := Last + 1;
 
                if Can_Have_Parameter (Switch) then
-
                   --  Include potential parameter to the recursive call.
                   --  Only numbers are allowed.
 
@@ -1989,8 +2015,10 @@ 
       --  First determine if the switch corresponds to one belonging to the
       --  configuration. If so, run callback and exit.
 
+      --  ??? Is this necessary. On simple tests, we seem to have the same
+      --  results with or without this call.
+
       Foreach_In_Config (Config, Section);
-
       if Found_In_Config then
          return;
       end if;
@@ -2127,10 +2155,17 @@ 
          Param     : String;
          Index     : Integer)
       is
-         pragma Unreferenced (Index);
          Sep : Character;
 
       begin
+         if Index = -1
+           and then Cmd.Config /= null
+           and then not Cmd.Config.Star_Switch
+         then
+            raise Invalid_Switch
+              with "Invalid switch " & Simple;
+         end if;
+
          if Separator = "" then
             Sep := ASCII.NUL;
          else
@@ -2808,13 +2843,8 @@ 
       if Iter.List = null then
          Iter.Current := Integer'Last;
       else
-         Iter.Current := Iter.List'First;
-
-         while Iter.Current <= Iter.List'Last
-           and then Iter.List (Iter.Current) = null
-         loop
-            Iter.Current := Iter.Current + 1;
-         end loop;
+         Iter.Current := Iter.List'First - 1;
+         Next (Iter);
       end if;
    end Start;
 
Index: g-comlin.ads
===================================================================
--- g-comlin.ads	(revision 177274)
+++ g-comlin.ads	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                 S p e c                                  --
 --                                                                          --
---                     Copyright (C) 1999-2010, AdaCore                     --
+--                     Copyright (C) 1999-2011, AdaCore                     --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -583,6 +583,10 @@ 
    --  assumed that the remainder of the switch ("uv") is a set of characters
    --  whose order is irrelevant. In fact, this package will sort them
    --  alphabetically.
+   --  When grouping switches that accept arguments (for instance "-gnatyL!"
+   --  as the definition, and "-gnatyaL12b" as the command line), only
+   --  numerical arguments are accepted. The above is equivalent to
+   --  "-gnatya -gnatyL12 -gnatyb".
 
    procedure Define_Switch
      (Config      : in out Command_Line_Configuration;
@@ -768,7 +772,9 @@ 
       Config : Command_Line_Configuration);
    function Get_Configuration
      (Cmd : Command_Line) return Command_Line_Configuration;
-   --  Set or retrieve the configuration used for that command line
+   --  Set or retrieve the configuration used for that command line.
+   --  The Config must have been initialized first, by calling one of the
+   --  Define_Switches subprograms.
 
    procedure Set_Command_Line
      (Cmd                : in out Command_Line;
@@ -781,6 +787,8 @@ 
    --  The parsing of Switches is done through calls to Getopt, by passing
    --  Getopt_Description as an argument. (A "*" is automatically prepended so
    --  that all switches and command line arguments are accepted).
+   --  If a config was defined via Set_Configuration, the Getopt_Description
+   --  parameter will be ignored.
    --
    --  To properly handle switches that take parameters, you should document
    --  them in Getopt_Description. Otherwise, the switch and its parameter will
@@ -792,6 +800,12 @@ 
    --  should be listed in the Sections parameter (as "-bargs -cargs").
    --
    --  This function can be used to reset Cmd by passing an empty string.
+   --
+   --  If an invalid switch is found on the command line (ie wasn't defined in
+   --  the configuration via Define_Switch), and the configuration wasn't set
+   --  to accept all switches (by defining "*" as a valid switch), then an
+   --  exception Invalid_Switch is raised. The exception message indicates the
+   --  invalid switch.
 
    procedure Add_Switch
      (Cmd        : in out Command_Line;
@@ -1084,6 +1098,11 @@ 
       Sections : GNAT.OS_Lib.Argument_List_Access;
       --  The list of sections
 
+      Star_Switch : Boolean := False;
+      --  Whether switches not described in this configuration should be
+      --  returned to the user (True). If False, an exception Invalid_Switch
+      --  is raised.
+
       Aliases  : Alias_Definitions_List;
       Usage    : GNAT.OS_Lib.String_Access;
       Help     : GNAT.OS_Lib.String_Access;