Command Line Subcommands in Ada

Here’s the translation of the Go code to Ada, with explanations in Markdown format suitable for Hugo:

Our program demonstrates the use of subcommands in Ada, similar to how tools like git have different subcommands (e.g., git pull, git push). We’ll use the GNAT.Command_Line package to parse command-line arguments and implement subcommands.

with Ada.Text_IO;
with Ada.Command_Line;
with GNAT.Command_Line;

procedure Command_Line_Subcommands is
   use Ada.Text_IO;
   use Ada.Command_Line;
   use GNAT.Command_Line;

   procedure Handle_Foo is
      Enable : Boolean := False;
      Name   : String(1..100) := (others => ' ');
      Name_Last : Natural := 0;
   begin
      loop
         case Getopt ("e n:") is
            when 'e' =>
               Enable := True;
            when 'n' =>
               Name(1..Full_Switch'Length) := Full_Switch;
               Name_Last := Full_Switch'Length;
            when others =>
               exit;
         end case;
      end loop;

      Put_Line ("subcommand 'foo'");
      Put_Line ("  enable: " & Boolean'Image(Enable));
      Put_Line ("  name: " & Name(1..Name_Last));
      Put ("  tail:");
      for I in 1..Argument_Count loop
         Put (" " & Argument(I));
      end loop;
      New_Line;
   end Handle_Foo;

   procedure Handle_Bar is
      Level : Integer := 0;
   begin
      loop
         case Getopt ("l:") is
            when 'l' =>
               Level := Integer'Value(Parameter);
            when others =>
               exit;
         end case;
      end loop;

      Put_Line ("subcommand 'bar'");
      Put_Line ("  level: " & Integer'Image(Level));
      Put ("  tail:");
      for I in 1..Argument_Count loop
         Put (" " & Argument(I));
      end loop;
      New_Line;
   end Handle_Bar;

begin
   if Argument_Count < 1 then
      Put_Line ("expected 'foo' or 'bar' subcommands");
      Set_Exit_Status (Failure);
      return;
   end if;

   if Argument(1) = "foo" then
      Initialize_Option_Scan (1);
      Handle_Foo;
   elsif Argument(1) = "bar" then
      Initialize_Option_Scan (1);
      Handle_Bar;
   else
      Put_Line ("expected 'foo' or 'bar' subcommands");
      Set_Exit_Status (Failure);
   end if;
end Command_Line_Subcommands;

This Ada program implements subcommands similar to the original example. Here’s how it works:

  1. We use the GNAT.Command_Line package to parse command-line arguments.

  2. We define two procedures, Handle_Foo and Handle_Bar, to handle the “foo” and “bar” subcommands respectively.

  3. In the main procedure, we check if a subcommand is provided and call the appropriate handler.

  4. Each handler uses Getopt to parse its specific flags and then prints the results.

To compile and run the program:

$ gnatmake command_line_subcommands.adb
$ ./command_line_subcommands foo -e -n=joe a1 a2
subcommand 'foo'
  enable: TRUE
  name: joe
  tail: a1 a2

$ ./command_line_subcommands bar -l 8 a1
subcommand 'bar'
  level: 8
  tail: a1

Note that Ada’s command-line parsing is somewhat different from the Go example. We use short options (-e, -n, -l) instead of long options, and the syntax for specifying option values is slightly different.

If you try to use an undefined flag, Ada will raise an exception:

$ ./command_line_subcommands bar -e a1
raised PROGRAM_ERROR : command_line_subcommands.adb:61 bad option: e

This example demonstrates how to implement subcommands and parse command-line arguments in Ada, providing similar functionality to the original Go program.