* 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