--  psh2.adb
--    Prompting shell (version 2).
--      Prompts for the command and its arguments.
--      Builds the argument vector for the call to execvp.
--      Uses execvp and never returns.

with
  Ada.Strings.Unbounded,
  Ada.Strings.Unbounded.Text_IO,
  Ada.Text_IO,
  Interfaces.C.Strings,
  System,
  Unchecked_Conversion,
  POSIX.Process_Primitives;

with Fork, Wait;
with Process_Termination;

procedure Prompting_Shell_2 is
   package size_t_Text_IO is new Ada.Text_IO.Modular_IO (Interfaces.C.size_t);

   type chars_ptr_ptr is access constant Interfaces.C.Strings.chars_ptr;
   pragma Convention (C, chars_ptr_ptr);
   function To_Ptr is new Unchecked_Conversion (System.Address, chars_ptr_ptr);

   procedure Execute (Arguments : in     Interfaces.C.Strings.chars_ptr_array) is
      procedure execvp (path : Interfaces.C.Strings.chars_ptr;
			argv : chars_ptr_ptr);
      pragma Import (C, execvp, "execvp");
      
      use type Interfaces.C.int;
      
      Child        : Interfaces.C.int;
      Child_Status : aliased Interfaces.C.int;
   begin
      Child := Fork;
      if Child < 0 then
	 Ada.Text_IO.Put_Line (File => Ada.Text_IO.Standard_Error,
                               Item => "fork() failed.");
         POSIX.Process_Primitives.Exit_Process (Status => 1);
      elsif Child = 0 then
	 execvp (path => Arguments (0),
		 argv => To_Ptr (Arguments'Address));
	 Ada.Text_IO.Put_Line (File => Ada.Text_IO.Standard_Error,
                               Item => "execvp() failed.");
         POSIX.Process_Primitives.Exit_Process (Status => 1);
      else
	 loop
	    exit when Wait (Child_Status'Access) = Child;
	 end loop;
	 
	 Ada.Text_IO.Put ("Child exited with status: exit =");
	 Ada.Text_IO.Put (Process_Termination.Exit_Status'Image
                            (Process_Termination.Exit_Code (Child_Status)));
	 Ada.Text_IO.Put (" signal =");
	 Ada.Text_IO.Put (Process_Termination.POSIX_Signal'Image
                            (Process_Termination.Signal (Child_Status)));
	 Ada.Text_IO.Put (" core = ");
	 Ada.Text_IO.Put
           (Boolean'Image (Process_Termination.Core_Dumped (Child_Status)));
	 Ada.Text_IO.New_Line;
      end if;
   end Execute;
   
   use type Ada.Strings.Unbounded.Unbounded_String;
   use type Interfaces.C.size_t;

   Arguments      : Interfaces.C.Strings.chars_ptr_array (0 .. 20);
   Argument_count : Interfaces.C.size_t := Arguments'First;
   Argument       : Ada.Strings.Unbounded.Unbounded_String;
begin
   while Argument_Count < Arguments'Last loop
      Ada.Text_IO.Put ("Arg[");
      size_t_Text_IO.Put (Argument_Count, Width => 0);
      Ada.Text_IO.Put ("]? ");
      Argument := Ada.Strings.Unbounded.Text_IO.Get_Line;
      if Argument = Ada.Strings.Unbounded.Null_Unbounded_String then
         if Argument_Count > Arguments'First then
            Arguments (Argument_Count) := Interfaces.C.Strings.Null_Ptr;
            Execute (Arguments);
            Argument_Count := 0;
         end if;
      else
         Arguments (Argument_Count) := Interfaces.C.Strings.New_String (Ada.Strings.Unbounded.To_String (Argument));
         Argument_Count := Argument_Count + 1;
      end if;
   end loop;
end Prompting_Shell_2;

