Unix Programming - Writing a unix command prompt

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > January 2006 > Writing a unix command prompt





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author Writing a unix command prompt
repairman2003@gmail.com

2006-01-29, 9:32 pm

I'm writing a command prompt for unix and I've run into some problems:


#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#define EXIT "exit"
#define DELIMITER " "
we are in
int main(argc, argv)
{
//Initilzation of varibles
char **arguments = (char **) malloc (8);
char *command_buffer = (char *) malloc (256);
char *arg_ptr;
int i = 0;
int pid;
int nbytes = 256;
int not_exiting = 1;


do{
//prints prompt and gets line of text
printf("sim> ");
getline(&command_buffer, &nbytes, stdin);


//Special workaround
//replaced the '\n' at the end of the input, which was
giving errors
//with '\0'
command_buffer[strlen(command_buffer) -1] = '\0';


//picks line apart and
//replaces spaces with '\0' and adds pointers to
argument[]
do{
if(i == 0)
{
arguments[i] = strtok(command_buffer,
DELIMITER);
i++;
}
else
{
arg_ptr = strtok(NULL, DELIMITER);


if(arg_ptr != NULL)
{
arguments[i] = arg_ptr;
i++;
}
else
{
i++;
break;
}
}
}while(1);


//are we exiting?
not_exiting = strcmp(command_buffer, EXIT);
if(not_exiting)
{
//create child process
pid = fork();


if(pid == 0) //fork() == 0 means child
process
{
execvp(*arguments, arguments);
exit(0);
}
else if(pid > 0) //fork() > 0 means we are in
parent process
{


wait(NULL);
}
else //otherwise we have error
{
fprintf(stderr, "fork() returned
error");
exit(1);
}
}
else
{
printf("Exiting\n");
}
}while(not_exiting);


return 0;



}


The problems
1. The workaround listed above.
2. One argument commands work fine but multiple doesn't. Eg. ls -a
works fine, ls -al works fine but ls -a -l doesn't work. Any
subsequent commands that don't have arguments don't work either, eg.
ls works, then ls -a works, but ls again doesn't work.

Any help is greatly appriciated!

Robert Harris

2006-01-29, 9:32 pm

repairman2003@gmail.com wrote:
> I'm writing a command prompt for unix and I've run into some problems:
>
> [snip]
>
> The problems
> 1. The workaround listed above.
> 2. One argument commands work fine but multiple doesn't. Eg. ls -a
> works fine, ls -al works fine but ls -a -l doesn't work. Any
> subsequent commands that don't have arguments don't work either, eg.
> ls works, then ls -a works, but ls again doesn't work.
>
> Any help is greatly appriciated!

use getopt(3) to parse your command line.

Robert
>

Stephan Brönnimann

2006-01-29, 9:32 pm

repairman2003@gmail.com wrote:
> I'm writing a command prompt for unix and I've run into some problems:
>
>
> #include <stdio.h>
> #include <string.h>
> #include <unistd.h>
> #include <sys/types.h>
> #include <sys/wait.h>
> #include <stdlib.h>
> #define EXIT "exit"
> #define DELIMITER " "
> we are in
> int main(argc, argv)
> {
> //Initilzation of varibles
> char **arguments = (char **) malloc (8);
> char *command_buffer = (char *) malloc (256);
> char *arg_ptr;
> int i = 0;
> int pid;
> int nbytes = 256;
> int not_exiting = 1;
>
>
> do{
> //prints prompt and gets line of text
> printf("sim> ");
> getline(&command_buffer, &nbytes, stdin);
>
>
> //Special workaround
> //replaced the '\n' at the end of the input, which was
> giving errors
> //with '\0'
> command_buffer[strlen(command_buffer) -1] = '\0';
>
>
> //picks line apart and
> //replaces spaces with '\0' and adds pointers to
> argument[]
> do{
> if(i == 0)
> {
> arguments[i] = strtok(command_buffer,
> DELIMITER);
> i++;
> }
> else
> {
> arg_ptr = strtok(NULL, DELIMITER);
>
>
> if(arg_ptr != NULL)
> {
> arguments[i] = arg_ptr;
> i++;
> }
> else
> {
> i++;
> break;
> }
> }
> }while(1);
>
>
> //are we exiting?
> not_exiting = strcmp(command_buffer, EXIT);
> if(not_exiting)
> {
> //create child process
> pid = fork();
>
>
> if(pid == 0) //fork() == 0 means child
> process
> {
> execvp(*arguments, arguments);
> exit(0);
> }
> else if(pid > 0) //fork() > 0 means we are in
> parent process
> {
>
>
> wait(NULL);
> }
> else //otherwise we have error
> {
> fprintf(stderr, "fork() returned
> error");
> exit(1);
> }
> }
> else
> {
> printf("Exiting\n");
> }
> }while(not_exiting);
>
>
> return 0;
>
>
>
> }
>
>
> The problems
> 1. The workaround listed above.
> 2. One argument commands work fine but multiple doesn't. Eg. ls -a
> works fine, ls -al works fine but ls -a -l doesn't work. Any
> subsequent commands that don't have arguments don't work either, eg.
> ls works, then ls -a works, but ls again doesn't work.
>
> Any help is greatly appriciated!


You have at least two errors:
+ `i' is not initialized in the command line break-down part
+ execvp expects a NULL-terminated array:
- arguments[0] = "ls"
- argumetnts[1]= NULL

Replace the "strtok" block with:
//picks line apart and
//replaces spaces with '\0' and adds pointers to argument[]
i = 0;
arguments[i] = strtok(command_buffer, DELIMITER);
while (NULL != arguments[i]) {
++i;
arguments[i] = strtok(NULL, DELIMITER);
}

Stephan

Stephan Brönnimann

2006-01-29, 9:32 pm

repairman2003@gmail.com wrote:
> I'm writing a command prompt for unix and I've run into some problems:
>
>
> #include <stdio.h>
> #include <string.h>
> #include <unistd.h>
> #include <sys/types.h>
> #include <sys/wait.h>
> #include <stdlib.h>
> #define EXIT "exit"
> #define DELIMITER " "
> we are in
> int main(argc, argv)
> {
> //Initilzation of varibles
> char **arguments = (char **) malloc (8);
> char *command_buffer = (char *) malloc (256);
> char *arg_ptr;
> int i = 0;
> int pid;
> int nbytes = 256;
> int not_exiting = 1;
>
>
> do{
> //prints prompt and gets line of text
> printf("sim> ");
> getline(&command_buffer, &nbytes, stdin);
>
>
> //Special workaround
> //replaced the '\n' at the end of the input, which was
> giving errors
> //with '\0'
> command_buffer[strlen(command_buffer) -1] = '\0';
>
>
> //picks line apart and
> //replaces spaces with '\0' and adds pointers to
> argument[]
> do{
> if(i == 0)
> {
> arguments[i] = strtok(command_buffer,
> DELIMITER);
> i++;
> }
> else
> {
> arg_ptr = strtok(NULL, DELIMITER);
>
>
> if(arg_ptr != NULL)
> {
> arguments[i] = arg_ptr;
> i++;
> }
> else
> {
> i++;
> break;
> }
> }
> }while(1);
>
>
> //are we exiting?
> not_exiting = strcmp(command_buffer, EXIT);
> if(not_exiting)
> {
> //create child process
> pid = fork();
>
>
> if(pid == 0) //fork() == 0 means child
> process
> {
> execvp(*arguments, arguments);
> exit(0);
> }
> else if(pid > 0) //fork() > 0 means we are in
> parent process
> {
>
>
> wait(NULL);
> }
> else //otherwise we have error
> {
> fprintf(stderr, "fork() returned
> error");
> exit(1);
> }
> }
> else
> {
> printf("Exiting\n");
> }
> }while(not_exiting);
>
>
> return 0;
>
>
>
> }
>
>
> The problems
> 1. The workaround listed above.
> 2. One argument commands work fine but multiple doesn't. Eg. ls -a
> works fine, ls -al works fine but ls -a -l doesn't work. Any
> subsequent commands that don't have arguments don't work either, eg.
> ls works, then ls -a works, but ls again doesn't work.
>
> Any help is greatly appriciated!


You have at least two errors:
+ `i' is not initialized in the command line break-down part
+ execvp expects a NULL-terminated array:
- arguments[0] = "ls"
- arguments[1] = NULL

Replace the "strtok" block with:
//picks line apart and
//replaces spaces with '\0' and adds pointers to argument[]
i = 0;
arguments[i] = strtok(command_buffer, DELIMITER);
while (NULL != arguments[i]) {
++i;
arguments[i] = strtok(NULL, DELIMITER);
}

Stephan

Stephan Brönnimann

2006-01-29, 9:32 pm

repairman2003@gmail.com wrote:
> I'm writing a command prompt for unix and I've run into some problems:
>
>
> #include <stdio.h>
> #include <string.h>
> #include <unistd.h>
> #include <sys/types.h>
> #include <sys/wait.h>
> #include <stdlib.h>
> #define EXIT "exit"
> #define DELIMITER " "
> we are in
> int main(argc, argv)
> {
> //Initilzation of varibles
> char **arguments = (char **) malloc (8);
> char *command_buffer = (char *) malloc (256);
> char *arg_ptr;
> int i = 0;
> int pid;
> int nbytes = 256;
> int not_exiting = 1;
>
>
> do{
> //prints prompt and gets line of text
> printf("sim> ");
> getline(&command_buffer, &nbytes, stdin);
>
>
> //Special workaround
> //replaced the '\n' at the end of the input, which was
> giving errors
> //with '\0'
> command_buffer[strlen(command_buffer) -1] = '\0';
>
>
> //picks line apart and
> //replaces spaces with '\0' and adds pointers to
> argument[]
> do{
> if(i == 0)
> {
> arguments[i] = strtok(command_buffer,
> DELIMITER);
> i++;
> }
> else
> {
> arg_ptr = strtok(NULL, DELIMITER);
>
>
> if(arg_ptr != NULL)
> {
> arguments[i] = arg_ptr;
> i++;
> }
> else
> {
> i++;
> break;
> }
> }
> }while(1);
>
>
> //are we exiting?
> not_exiting = strcmp(command_buffer, EXIT);
> if(not_exiting)
> {
> //create child process
> pid = fork();
>
>
> if(pid == 0) //fork() == 0 means child
> process
> {
> execvp(*arguments, arguments);
> exit(0);
> }
> else if(pid > 0) //fork() > 0 means we are in
> parent process
> {
>
>
> wait(NULL);
> }
> else //otherwise we have error
> {
> fprintf(stderr, "fork() returned
> error");
> exit(1);
> }
> }
> else
> {
> printf("Exiting\n");
> }
> }while(not_exiting);
>
>
> return 0;
>
>
>
> }
>
>
> The problems
> 1. The workaround listed above.
> 2. One argument commands work fine but multiple doesn't. Eg. ls -a
> works fine, ls -al works fine but ls -a -l doesn't work. Any
> subsequent commands that don't have arguments don't work either, eg.
> ls works, then ls -a works, but ls again doesn't work.
>
> Any help is greatly appriciated!


You have at least two errors:
+ `i' is not initialized in the command line break-down part
+ execvp expects a NULL-terminated array:
- arguments[0] = "ls"
- argumetnts[1]= NULL

Replace the "strtok" block with:
//picks line apart and
//replaces spaces with '\0' and adds pointers to argument[]
i = 0;
arguments[i] = strtok(command_buffer, DELIMITER);
while (NULL != arguments[i]) {
++i;
arguments[i] = strtok(NULL, DELIMITER);
}

Stephan

Barry Margolin

2006-01-29, 9:32 pm

In article <1O3Df.215188$D47.8103@fe3.news.blueyonder.co.uk>,
Robert Harris <robert.f.harris@blueyonder.co.uk> wrote:

> repairman2003@gmail.com wrote:
> use getopt(3) to parse your command line.


getopt() is something that can be used in the program that gets
executed, it has nothing to do with parsing by the shell itself.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
Pascal Bourguignon

2006-01-29, 9:32 pm

repairman2003@gmail.com writes:

> I'm writing a command prompt for unix and I've run into some problems:
> [...some includes...]
> [...one function of 94 lines...]
>
> The problems
> 1. The workaround listed above.
> 2. One argument commands work fine but multiple doesn't. Eg. ls -a
> works fine, ls -al works fine but ls -a -l doesn't work. Any
> subsequent commands that don't have arguments don't work either, eg.
> ls works, then ls -a works, but ls again doesn't work.


No. The problem is this single 94-line function.
As a rule of thumb, any function that's more than 24 lines is too big.
But the point is to define and implement abstractions, and to write
simple routines in function of these abstractions.

If you have commands with arguments, then a program written as:

{
command_line_t* cmd=read_command_line(input_stream);
word_list_t* words=parse_command_line(cmd);
string_t* pgm=first(words);
word_list_t* arguments=rest(words);
fork_and_execute(pgm,arguments);
}

IS CORRECT! (given the abstractions are correctly implemented).


--
__Pascal Bourguignon__ http://www.informatimago.com/

"You cannot really appreciate Dilbert unless you read it in the
original Klingon"
Chris F.A. Johnson

2006-01-29, 9:32 pm

On 2006-01-29, Barry Margolin wrote:
> In article <1O3Df.215188$D47.8103@fe3.news.blueyonder.co.uk>,
> Robert Harris <robert.f.harris@blueyonder.co.uk> wrote:
>
>
> getopt() is something that can be used in the program that gets
> executed, it has nothing to do with parsing by the shell itself.


You can feed any array to getopt. The command line just has to be
parsed into an array first.

--
Chris F.A. Johnson, author | <http://cfaj.freeshell.org>
Shell Scripting Recipes: | My code in this post, if any,
A Problem-Solution Approach | is released under the
2005, Apress | GNU General Public Licence
Barry Margolin

2006-01-29, 9:32 pm

In article <huvva3-ecj.ln1@teksavvy.com>,
"Chris F.A. Johnson" <cfajohnson@gmail.com> wrote:

> On 2006-01-29, Barry Margolin wrote:
>
> You can feed any array to getopt. The command line just has to be
> parsed into an array first.


Right. But the program he's having trouble writing is the one that does
the parsing into an array. He's then trying to execute a program like
ls, which might or might not use getopt() internally.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
Henry Townsend

2006-01-29, 9:32 pm

Barry Margolin wrote:
> getopt() is something that can be used in the program that gets
> executed, it has nothing to do with parsing by the shell itself.


With the caveat that the getopt(1) program is available, and that the
POSIX shell has a 'getopts' builtin.
Barry Margolin

2006-01-29, 9:32 pm

In article <I7OdnYYn4dFP60DeRVn-uA@comcast.com>,
Henry Townsend <henry.townsend@not.here> wrote:

> Barry Margolin wrote:
>
> With the caveat that the getopt(1) program is available, and that the
> POSIX shell has a 'getopts' builtin.


So? The OP is writing his own shell, he's not using some existing
shell, so it doesn't matter what some other shell has built in. In the
context of a POSIX shell, getopt(1) is something that would be used by a
script, but not by the shell itself to perform word splitting.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com