comp.lang.ada
 help / color / mirror / Atom feed
* Help with constructing an Ada Shell
@ 2015-10-30  4:53 annihilan
  2015-10-30  8:37 ` Jacob Sparre Andersen
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: annihilan @ 2015-10-30  4:53 UTC (permalink / raw)


Okay. So I've been trying to learn Ada recently, which unfortunately means that my question isn't going to be very sophisticated. I have the following code:

with Ada.Text_IO; use Ada.Text_IO;

with GNAT.OS_Lib; use GNAT.OS_Lib;
with GNAT.Strings;

package body Ada_Shell is
   Input : aliased String := (1 .. 255 => ' ');
   Last : Integer;
   procedure Main is
      package IO renames Ada.Text_IO;
   begin
      IO.Put_Line("Welcome to ash! This is an extreme work in progress.");
  Main_Loop:
      loop
	 Input := (others=> ' ');
	 IO.Put("ash> ");
	 IO.Get_Line(Input, Last);
	 if Input(Input'First..Last) = "quit" then
	    exit Main_Loop;
	 else
	    Execute_System;
	 end if;
      end loop Main_Loop;
   end Main;
   
   procedure Execute_System is
      Result : Integer;
      Arguments : Argument_List :=
	(1 => Input'Access);
   begin
      Spawn (Program_Name => Input, -- truncate strings or Input(Input'First..Last)??
	     Args => Arguments,
	     Output_File_Descriptor => Standout,
	     Return_Code => Result);
      --  for Index in Arguments'Range loop
      --  	 Free(Arguments(Index));
      --  end loop;
      Put_Line(Integer'Image(Result));
   end Execute_System;
end Ada_Shell;

This code is executed by a simple procedure that calls the Main loop of the package. I don't know if there's a "better" way to make a repeating main loop like this, but I couldn't contrive a better solution. 
Besides, this code does not work. It compiles, sure, but it doesn't work. No matter what command is passed at the prompt, a return value of 1 is given. 

Things I have tried that work:
hardcoding the program at Spawn(Program_Name=>"/bin/ls") or similar

Things I have tried that have not worked:
Having Execute_System be in a separate file, and having its signature as Execute_System(Command:access String) (this worked especially poorly, bringing in aliasing problems that I couldn't solve.

I really don't know why this doesn't work. The reason that the result code and command line are global was to eliminate "non-local pointer references local object" and "implicit conversion of anonymous access formal" errors. I haven't tried uncommenting the Free block since I fixed everything, though.

I would massively appreciate any help that could be given to me. I don't really have any clue at all what's going on.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with constructing an Ada Shell
  2015-10-30  4:53 Help with constructing an Ada Shell annihilan
@ 2015-10-30  8:37 ` Jacob Sparre Andersen
  2015-11-03  0:47   ` Nick Gordon
  2015-10-30  9:10 ` Simon Wright
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Jacob Sparre Andersen @ 2015-10-30  8:37 UTC (permalink / raw)


annihilan@gmail.com writes:

>    Input : aliased String := (1 .. 255 => ' ');

> 	 IO.Get_Line(Input, Last);

>       Spawn (Program_Name => Input, -- truncate strings or Input(Input'First..Last)??

> No matter what command is passed at the prompt, a return value of 1 is
> given. 

Have you tried passing a command whose name is exactly 255 characters
long?

> I would massively appreciate any help that could be given to me. I
> don't really have any clue at all what's going on.

"Global" variables, which aren't really about maintaining state, are
generally a bad idea.

Why don't you give Execute_System the profile:

   function Execute_System (Program : in String) return Integer;

If GNAT.OS_Lib.Spawn wants access types as parameters, you can always
allocate a copy on the heap inside Execute_System and pass the access to
the copy to GNAT.OS_Lib.Spawn.

Greetings,

Jacob
-- 
                      CAUTION
               BLADE EXTREMELY SHARP
                KEEP OUT OF CHILDREN


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with constructing an Ada Shell
  2015-10-30  4:53 Help with constructing an Ada Shell annihilan
  2015-10-30  8:37 ` Jacob Sparre Andersen
@ 2015-10-30  9:10 ` Simon Wright
  2015-10-30 13:52 ` David Botton
  2015-10-30 23:19 ` Xavier Petit
  3 siblings, 0 replies; 6+ messages in thread
From: Simon Wright @ 2015-10-30  9:10 UTC (permalink / raw)


(1) I don't know why you want to use access String at all, at any rate
for the command (I see that Argument_List involves access to strings,
necessary in Ada to support ragged arrays).

(2) Spawn.Program_Name is the program to be spawned, Spawn.Arguments are
the arguments to that program, and shouldn't include the program unless
you want to execute it on itself.

(3) Wasn't there a discussion here recently about needing to supply the
full path to the program? (e.g. "/bin/ls" - I think you may have this
sorted already)

(4) The code you've posted doesn't compile.

The code below "works" provided the command you give it is "/bin/ls" - I
converted it into a procedure, & I haven't bothered with parsing the
command into Program_Name and Arguments, or with cleanup.

with Ada.Text_IO; use Ada.Text_IO;

with GNAT.OS_Lib; use GNAT.OS_Lib;
with GNAT.Strings;

procedure Ada_Shell is
   procedure Execute_System (Command : String);
   procedure Main is
      package IO renames Ada.Text_IO;
   begin
      IO.Put_Line("Welcome to ash! This is an extreme work in progress.");
      Main_Loop:
      loop
	 IO.Put("ash> ");
         declare
            Input : constant String := IO.Get_Line;
         begin
	    if Input = "quit" then
	       exit Main_Loop;
	    else
	       Execute_System (Input);
	    end if;
         end;
      end loop Main_Loop;
   end Main;

   procedure Execute_System (Command : String) is
      Result : Integer;
      Arguments : Argument_List := (1 => new String'("ada_shell.adb"));
   begin
      Spawn (Program_Name => Command,
	     Args => Arguments,
	     Output_File_Descriptor => Standout,
	     Return_Code => Result);
      Put_Line(Integer'Image(Result));
   end Execute_System;
begin
   Main;
end Ada_Shell;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with constructing an Ada Shell
  2015-10-30  4:53 Help with constructing an Ada Shell annihilan
  2015-10-30  8:37 ` Jacob Sparre Andersen
  2015-10-30  9:10 ` Simon Wright
@ 2015-10-30 13:52 ` David Botton
  2015-10-30 23:19 ` Xavier Petit
  3 siblings, 0 replies; 6+ messages in thread
From: David Botton @ 2015-10-30 13:52 UTC (permalink / raw)


Take a look in the Gnoga project at src/gnoga-server-template_parser-python.adb for examples of spawning and using the results of a process, etc. (http://gnoga.com)

David Botton


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with constructing an Ada Shell
  2015-10-30  4:53 Help with constructing an Ada Shell annihilan
                   ` (2 preceding siblings ...)
  2015-10-30 13:52 ` David Botton
@ 2015-10-30 23:19 ` Xavier Petit
  3 siblings, 0 replies; 6+ messages in thread
From: Xavier Petit @ 2015-10-30 23:19 UTC (permalink / raw)


Hello, I would suggest you to learn Ada with more easy and abstract 
stuff, not shells ^^ which are platform dependent and related to the 
Unix/C philosophy.
GNAT provides OS abstraction but I think that dealing with process 
spawning is not the best way to learn Ada.

Here a working example of what you wanna do, based on previous answers.
(Sorry for my terrible english)

with Ada.Text_IO,
      GNAT.OS_Lib;

procedure Ada_Shell is
    procedure Execute_System (Command : String)
    is
       use GNAT.OS_Lib;

       List : String_List_Access := Argument_String_To_List (Command);
       Exec_Path : String_Access := Locate_Exec_On_Path (List (1).all);
       Success : Boolean;

    begin
       if Exec_Path /= null then
          Spawn (Program_Name => Exec_Path.all,
                 Args         => List (2 .. List'Last),
                 Success      => Success);
          Free (Exec_Path);
       else
          Ada.Text_IO.Put_Line ("Command not found");
       end if;

       Free (List);
    end Execute_System;

begin
    Main : loop
       Ada.Text_IO.Put ("ash> ");

       declare
          Input : constant String := Ada.Text_IO.Get_Line;
       begin
          exit Main when Input = "exit";

          if Input'Length > 0 then
             Execute_System (Command => Input);
          end if;
       end;
    end loop Main;

exception
    when Ada.Text_IO.End_Error => null; -- Handling [Ctrl]-[D]
end Ada_Shell;

-- 
Xavier Petit

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with constructing an Ada Shell
  2015-10-30  8:37 ` Jacob Sparre Andersen
@ 2015-11-03  0:47   ` Nick Gordon
  0 siblings, 0 replies; 6+ messages in thread
From: Nick Gordon @ 2015-11-03  0:47 UTC (permalink / raw)


On Friday, October 30, 2015 at 3:37:46 AM UTC-5, Jacob Sparre Andersen wrote:
> annihilan@gmail.com writes:
> 
> >    Input : aliased String := (1 .. 255 => ' ');
> 
> > 	 IO.Get_Line(Input, Last);
> 
> >       Spawn (Program_Name => Input, -- truncate strings or Input(Input'First..Last)??
> 
> > No matter what command is passed at the prompt, a return value of 1 is
> > given. 
> 
> Have you tried passing a command whose name is exactly 255 characters
> long?
> 
> > I would massively appreciate any help that could be given to me. I
> > don't really have any clue at all what's going on.
> 
> "Global" variables, which aren't really about maintaining state, are
> generally a bad idea.
> 
> Why don't you give Execute_System the profile:
> 
>    function Execute_System (Program : in String) return Integer;
> 
> If GNAT.OS_Lib.Spawn wants access types as parameters, you can always
> allocate a copy on the heap inside Execute_System and pass the access to
> the copy to GNAT.OS_Lib.Spawn.
> 
> Greetings,
> 
> Jacob
> -- 
>                       CAUTION
>                BLADE EXTREMELY SHARP
>                 KEEP OUT OF CHILDREN

The idea of copying the string to the heap and using the copy is sort of what I was going for. I haven't had the time to figure out how exactly to allocate a copy to the function's heap, but I'm currently working that out. I'll report back after I figure this out. Thanks to you and the others for the help.


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-11-03  0:47 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-30  4:53 Help with constructing an Ada Shell annihilan
2015-10-30  8:37 ` Jacob Sparre Andersen
2015-11-03  0:47   ` Nick Gordon
2015-10-30  9:10 ` Simon Wright
2015-10-30 13:52 ` David Botton
2015-10-30 23:19 ` Xavier Petit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox