|
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 ***
|
|
|
|
|