Unix Shell Source Code
Unix Source Code – CRA Shell
Coded By Conrad Brookes
Published under GNU Free Documentation License
This page contains a complete shell program together with a complete explanation on how to compile and run along with the testing.
This study is a code designed to construct a shell that runs on a UNIX operating system. The program should be able to mimic any other shell that runs on a UNIX machine such as BASH. This program is written in the c programming language and must be built and run from a UNIX operating system.
Installation
The shell program crash needs the files parser.c, parser.h, and main.c. Also a make file: Makefile if compiling from the shell command prompt. Either creating a project with an IDE or typing make within the directory with the files in it will build the program.
Discussion
The way I approached it was to use the command line parser that was supplied, and also the main that was supplied. I added a function to the inside the main.c file called proCom. This method processes all the arguments, for communication between the command line and the operating system. It handles any of the common functions that are performed by the shell. These tasks include handling piping, redirection, background processing, exit, prompt and directory walking. As per requirements the directory walk, prompt change and exit are built in commands, that is they are defined by myself and they do use any major external functions. The rest of the handling is achieved though the use of UNIX system calls such as fork and dup2.
The handling of sequential commands is processes within parser.c, in the function process_cmd_line. The way it is accomplished is by handling the ‘;’ in exactly the same way the pipe is handled. I quite literally cut and pasted the pervious code in that function.
Limitations
There are a number of limitations to this program. The program does not handle wildcard expansion, it was removed from the program because of the faults in the coding. Also there is no error handling in the command line. That is if a command is entered incorrectly there is no notification to the user. Signal handling is also not added to this program.
Testing
Testing Table
Assignment 2 b310 testing
yes = X
no = No
Reconfigurable Prompt X
prompt X
prompt $
Directory Walk
cd X
cd /mnt X
Redirection
ls > data1.txt X
cat < data2.txt X
Pipes
ls | more X
ls -la | more X
Background
sleep 10 & X
sleep 10 X
Sequential commands
ls ; cd /mnt X
ls ; cd /mnt ; ps X
ls ; cd /mnt ; ps ; sleep 10 & X
sleep 20; ps -l X
Exit
exit X
Miscellaneous Commands
ls X
ls -la X
pwd X
man index X
mkdir new X
chmod 777 data.txt X
Wildcards NO
Quoted Tokens
cat “topic 10” X
Screen Dump
$ prompt
no new prompt given
$ prompt ?
? pwd
/home/admin/Desktop/a2Unidevelop/a2Uni/a2unidev/a2unidev
? cd ..
? pwd
/home/admin/Desktop/a2Unidevelop/a2Uni/a2unidev
? cd
getenv(HOME): Success
? pwd
/home/admin
? cd /Desktop/a2Unidevelop/a2Uni/a2unidev
? pwd
/home/admin
? cd Desktop
? pwd
/home/admin/Desktop
? cd a2Unidevelop
? pwd
/home/admin/Desktop/a2Unidevelop
? cd a2Uni
? pwd
/home/admin/Desktop/a2Unidevelop/a2Uni
? cd a2unidev
? pwd
/home/admin/Desktop/a2Unidevelop/a2Uni/a2unidev
? cat > new
this is some text
? ls
Makefile a2unidev config.cache config.status missing stamp-h.in
Makefile.am a2unidev.kdevprj config.h configure mkinstalldirs
Makefile.dist acconfig.h config.h.in configure.in new
Makefile.in aclocal.m4 config.log install-sh stamp-h
? cat new
this is some text
? cat < new this is some text ? rm new ? ls Makefile a2unidev config.cache config.status missing Makefile.am a2unidev.kdevprj config.h configure mkinstalldirs Makefile.dist acconfig.h config.h.in configure.in stamp-h Makefile.in aclocal.m4 config.log install-sh stamp-h.in ? ls Makefile a2unidev config.cache config.status missing Makefile.am a2unidev.kdevprj config.h configure mkinstalldirs Makefile.dist acconfig.h config.h.in configure.in stamp-h Makefile.in aclocal.m4 config.log install-sh stamp-h.in ? ls | more Makefile Makefile.am Makefile.dist Makefile.in a2unidev a2unidev.kdevprj acconfig.h aclocal.m4 config.cache config.h config.h.in config.log config.status configure configure.in install-sh missing mkinstalldirs stamp-h stamp-h.in ? sleep 4 ? sleep 4 & PID: 1204 ? ps PID TTY TIME CMD 1173 pts/4 00:00:00 bash 1174 pts/4 00:00:00 a2unidev 1204 pts/4 00:00:00 sleep 1205 pts/4 00:00:00 ps ? ps PID TTY TIME CMD 1173 pts/4 00:00:00 bash 1174 pts/4 00:00:00 a2unidev 1204 pts/4 00:00:00 sleep
1206 pts/4 00:00:00 ps
? ls ; cd .. ; ps
Makefile a2unidev config.cache config.status missing
Makefile.am a2unidev.kdevprj config.h configure mkinstalldirs
Makefile.dist acconfig.h config.h.in configure.in stamp-h
Makefile.in aclocal.m4 config.log install-sh stamp-h.in
PID TTY TIME CMD
1173 pts/4 00:00:00 bash
1174 pts/4 00:00:00 a2unidev
1204 pts/4 00:00:00 sleep
1209 pts/4 00:00:00 ps
? sleep 4 ; ls
0 2 a2.html main.c makefile parser.h parser.o readme.txt
1 Makefile.txt a2unidev main.o parser.c parser.html parser_test
? cat > quoted 1
this is a quoted file
? ls
0 2 a2.html main.c makefile parser.h parser.o quoted 1
1 Makefile.txt a2unidev main.o parser.c parser.html parser_test readme.txt
? cat quote 1
cat: quote: No such file or directory
A simple Command Line Parser.
Author : Michael Roberts mroberts@it.net.au of Murdoch University
Last Modification : 14/08/01
Permission granted by Author for use in B310
Modified by Nick Nelissen, who separated the parser function from the main function
and provided a new Makefile and squashed the odd bug….
? cat “quote 1”
cat: quote 1: No such file or directory
? cat “quoted 1”
this is a quoted file
? mkdir newDir
? ls
0 2 a2.html main.c makefile parser.c parser.html parser_test readme.txt
1 Makefile.txt a2unidev main.o newDir parser.h parser.o quoted 1
? ls -la
total 124
drwxr-xr-x 4 admin admin 4096 Oct 31 13:39 .
drwx—— 3 admin admin 4096 Oct 4 13:21 ..
-rw——- 1 admin admin 12288 Oct 4 13:21 .main.c.swp
-rw-r–r– 1 admin admin 328 Oct 5 14:32 0
-rw-r–r– 1 admin admin 328 Oct 5 14:32 1
-rw-r–r– 1 admin admin 328 Oct 5 14:32 2
-rwxr-xr-x 1 admin admin 229 Oct 4 13:21 Makefile.txt
-rwxr-xr-x 1 admin admin 11267 Oct 4 13:21 a2.html
drwxr-xr-x 3 admin admin 4096 Oct 31 11:44 a2unidev
-rwxr-xr-x 1 admin admin 1148 Oct 4 13:21 main.c
-rw-r–r– 1 admin admin 1528 Oct 4 13:21 main.o
-rwxr-xr-x 1 admin admin 229 Oct 4 13:21 makefile
drwxr-xr-x 2 admin admin 4096 Oct 31 13:39 newDir
-rwxr-xr-x 1 admin admin 10288 Oct 4 13:21 parser.c
-rwxr-xr-x 1 admin admin 1063 Oct 4 13:21 parser.h
-rwxr-xr-x 1 admin admin 2749 Oct 4 13:21 parser.html
-rw-r–r– 1 admin admin 5624 Oct 4 13:21 parser.o
-rwxr-xr-x 1 admin admin 18194 Oct 4 13:21 parser_test
-rw-r–r– 1 admin admin 22 Oct 31 11:48 quoted 1
-rwxr-xr-x 1 admin admin 328 Oct 4 13:21 readme.txt
? chmod 777 newDir
? ls -la
total 124
drwxr-xr-x 4 admin admin 4096 Oct 31 13:39 .
drwx—— 3 admin admin 4096 Oct 4 13:21 ..
-rw——- 1 admin admin 12288 Oct 4 13:21 .main.c.swp
-rw-r–r– 1 admin admin 328 Oct 5 14:32 0
-rw-r–r– 1 admin admin 328 Oct 5 14:32 1
-rw-r–r– 1 admin admin 328 Oct 5 14:32 2
-rwxr-xr-x 1 admin admin 229 Oct 4 13:21 Makefile.txt
-rwxr-xr-x 1 admin admin 11267 Oct 4 13:21 a2.html
drwxr-xr-x 3 admin admin 4096 Oct 31 11:44 a2unidev
-rwxr-xr-x 1 admin admin 1148 Oct 4 13:21 main.c
-rw-r–r– 1 admin admin 1528 Oct 4 13:21 main.o
-rwxr-xr-x 1 admin admin 229 Oct 4 13:21 makefile
drwxrwxrwx 2 admin admin 4096 Oct 31 13:39 newDir
-rwxr-xr-x 1 admin admin 10288 Oct 4 13:21 parser.c
-rwxr-xr-x 1 admin admin 1063 Oct 4 13:21 parser.h
-rwxr-xr-x 1 admin admin 2749 Oct 4 13:21 parser.html
-rw-r–r– 1 admin admin 5624 Oct 4 13:21 parser.o
-rwxr-xr-x 1 admin admin 18194 Oct 4 13:21 parser_test
-rw-r–r– 1 admin admin 22 Oct 31 11:48 quoted 1
-rwxr-xr-x 1 admin admin 328 Oct 4 13:21 readme.txt
? ls new*
ls: new*: No such file or directory
? ls new?ir
ls: new?ir: No such file or directory
? exit
Press Enter to continue!
Source Code
include “parser.h”
/
** proCom.c
** Programmer: C Brookes
** Date: 10/09/02
*/
/*
- main.c
- Author of part of the main function : Michael Roberts mroberts@it.net.au
- Modified 11/9/01 by Nick Nelissen, who speparated the main into a separate source
- file
/ / - This function reads one line of 256 characters from stdin. THis line of
- characters is then processed as a command line.
- The resulting array of structures is then displayed to stdout.
* - Arguments :
- None.
* - Returns :
- An integer representing the exit status.
*
*/
char newProm[20];
char readIn[20];
//pocess commands
void proCom(command * c)
{
int p[2], status = 0;
int z = 0, indexA, comCount, pipeing, i, j, k;
char *pipeArg[20];
pid_t pid;
indexA = 0;
comCount = 0;
while(c->argv[indexA] != NULL)
{
comCount++;
indexA++;
}//end while
//The way i set the first 3 if statements was influenced from
//this web page
// www-instruct.wccnet.org/~chassel/linux275/ClassNotes/process/myshell.htm
if(strcmp(c->com_name, “cd”) == 0)//if the command is cd
{
if(comCount == 1)//if there is only cd with no arguments
{
//this method getenv(“HOME”) was from this site
//www.cs.bsu.edu/homepages/dlsills/davis_myshell.html
chdir(getenv(“HOME”));//goto home directory
perror(“getenv(HOME)”);
}//end if
else if(comCount > 2)//if there are more than 1 arguments after cd
{
printf(“Too many commands\n”);
}//end else if
else
{
chdir(c->argv[1]);//else change to the directory after the cd
}//end else
}
else if(strcmp(c->com_name, “exit”) == 0)//if the command is exit
{
exit(0);//die
}//end else if
else if(strcmp(c->com_name, “prompt”) == 0)//if the command is prompt
{
if(c->argv[1] == NULL)//if there are no following arguemtns following “prompt”
{
printf(“no new prompt given\n”);//error message
}//end if
else
{
strcpy(newProm, c->argv[1]);//put new prompt into prompt
}//end else
}//end elseif
//wild card procssing would go here
//wildcard(c);
//check for pipe
else if(c->pipe_to == 1)//if we have pipeing
{
z=0;//loop to get the first commands of the pipe
while(zargv[z];//copy the commands to be piped
z++;
}//end while
pipeArg[z] = NULL;//make sure last element is a NULL
pipeing = 1;//so the next loop it will have access to piping
return;//gets rid of bug
}//end if
if (pipeing == 1)
{
switch(fork())//switch to spawn a child process to execute commands (pipe)
{
case -1:
perror(“fork error”);//if there is an error
exit(2);//die
case 0: //child
break;//goto processing
default: //parent
wait((int *)0);//this gets rid of this looping bug
return;//dido
}//end switch
//open the pipe
//taken from Unix System Programming Haviland pg 156
//open up the pipe and sheck for error
if(pipe(p) == -1)
{
printf(“pipe call”);
exit(1);
}//end if
//the child does the piping
switch(fork())
{
case -1://check for error
exit(2);
case 0: //child
close(p[0]);//close read file descriptor
dup2(p[1],1);//write to the pipe
execvp(pipeArg[0], pipeArg);//the command to execute to the pipe
exit(1);//shouldnt get here
perror(“fork error”);//error message
default: //parent
//printf(“gets here\n”);
close(p[1]);//close the write descriptor
dup2(p[0],0);//read from the pipe
execvp(c->argv[0], c->argv);//the command that reads from the pipe
//wait((int *)0);
//return;
// exit(1);
perror(“fork error”);//mmm
}//end switch
pipeing = 0;
}//end if
//process redirection
//if redirect has been entered
if((c->redirect_out != NULL) || (c->redirect_in != NULL))
{
switch(pid = fork())//start a fork
{
case -1://case for error
printf(“error on redirect fork\n”);
exit(2);
case 0: //child process
//i found an example of redirection and writing to file similar to
//what i was looking for at this web site :
// www-instruct.wccnet.org/~chassel/linux275/ClassNotes/process/myshell.htm
if (c->redirect_out != NULL)//if redirection out do this
{
//this if statement will look to c if there is a space at the start if the redirect
if (c->redirect_out[0] == 32)
{
i = strlen(c->redirect_out);//get the length of string
k=1;
for(j=0;j<=(i-1);j++)//loop trough and get the chars minus the space { //and put them in the new sting readIn[j] = c->redirect_out[k];
k++;
}
k++;
readIn[k] = ‘\0’;//make the last char a \0
strcpy( c->redirect_out, readIn);//now copy the new string back
}//end if
//these fuctions and a similar example was found here
//www.umsl.edu/~s1002145/msdos.html
freopen(c->redirect_out, “w”, stdout);//open this file for writing
execvp(c->com_name, c->argv);//executethe command to write to this open file
exit(1);//kill this child process
}//end if
if (c->redirect_in != NULL)//if redirection in is found
{
//this if statement will look to c if there is a space at the start if the redirect
if (c->redirect_in[0] == 32)
{
i = strlen(c->redirect_in);//get the length of string
k=1;
for(j=0;j<=(i-1);j++)//loop trough and get the chars minus the space { //and put them in the new sting readIn[j] = c->redirect_in[k];
k++;
}
k++;
readIn[k] = ‘\0’;//make the last char a \0
strcpy( c->redirect_in, readIn);//now copy the new string back
}//end if
//these fuctions and a similar example was found here
//www.umsl.edu/~s1002145/msdos.html
if((freopen(c->redirect_in, “r”, stdin)) == NULL)//open this file for writing
{
printf(“Could not open file for redirection\n”);//check for error
exit(1);
}
execvp(c->com_name, c->argv);//executethe command to read to this
}//end if
default: //parent
}//end switch
}//end if
else
{
//process left over coomand that dont match the other criteria
switch(pid = fork())//forking a child
{
case -1://if error
printf(“error on redirect fork\n”);
exit(2);
case 0: //child
execvp(c->com_name, c->argv);
//printf(“%s”,newProm);
exit(1);
default: //parent
//wait((int *)0);
//wait(&status);
}//end switch
//
}//end else
//taken from Unix System Programming Haviland pg 113
//part of the smallsh program for handeling background
//processes.
if(c -> background == 1)
{
printf(“PID: %d\n”,pid);
return(0);
}
if(waitpid(pid, &status, 0) == -1)
return(-1);
else
return(status);
}//ed proCom
int
main(void)
{
char *cmd;
int lc = 0;
char *c;
command **cl;
strcpy(newProm, “$”);
for(;;)
{
cmd = (char *) malloc(CMD_LENGTH);
printf(“%s “,newProm);
cmd = fgets(cmd, CMD_LENGTH, stdin);
c = index(cmd, ‘\n’);
*c = ‘\0’;
//printf(“Command Line : [%s] [%d]\n”, cmd, strlen(cmd));
cl = process_cmd_line(cmd, 1);
lc = 0;
while (cl[lc] != NULL) {
//dump_structure(cl[lc], lc);
//print_human_readable(cl[lc], lc);
proCom(cl[lc]);
lc++;
}//end while
clean_up(cl);
free(cmd);
}//end for
return 0;
} /*End of main() */
/*
- Parser.c
- A simple Command Line Parser.
- Author : Michael Roberts mroberts@it.net.au
- Last Modification : 14/08/01
*
*Modified by C. Brookes in proccess_cmd_line.
*The original code has been edited by cut and pasting the previous existing
*code, created by the previous author.
*/
include “parser.h”
//#define DEBUG
/*
- This function breakes the simple command token isolated in other functions
- into a sequence of arguments. Each argument is bounded by white-spaces, and
- there is no special character intepretation. The results are stored in the
- argv array of the result command structure.
* - Arguments :
- cmd – the string to be processed.
- result – the comand struct to store the results in.
* - Returns :
- None.
*
*/
void
process_simple_cmd(char *cmd, command * result)
{
char *dc;
int lpc = 1;
int i,j = 0;
char array1[CMD_LENGTH];
char array2[CMD_LENGTH];
char array3[CMD_LENGTH];
strncpy(array1, cmd, CMD_LENGTH);
ifdef DEBUG
fprintf(stderr,”process_simple_cmd\n”);
endif
/*No Spaces Means No Arguments. */
if (((dc = index(cmd, white_space[0])) == NULL
&& (dc = index(cmd, white_space[1])) == NULL)
&& (dc = index(cmd, (char) 9)) == NULL) {
result->com_name = strdup(cmd);
result->argv = realloc((void *) result->argv, sizeof(char *));
result->argv[0] = strdup(cmd);
}
else {
// nick modified this
/*Pull out the Command Name (i.e First Token) */
dc = strtok(cmd, white_space);
//dc = cmd;
ifdef DEBUG
fprintf(stderr,”[%s][%s]\n”,dc,cmd);
endif
result->com_name = strdup(dc);
//result->com_name = strdup(cmd);
// end nick
ifdef DEBUG
fprintf(stderr,”{1}\n”);
endif
result->argv = realloc((void *) result->argv, sizeof(char *));
ifdef DEBUG
fprintf(stderr,”{2}\n”);
endif
result->argv[0] = strdup(dc);
if(index(array1,34) != NULL)//process quotes
{
strncpy(array2, index(array1, 34), CMD_LENGTH);
for(i=0;array2[i+1]!=34;i++)
{
array3[i] = array2[i+1];
}
array3[i] = 0;
result->argv = realloc((void *) result->argv, (lpc + 1) * sizeof(char *));
result->argv[lpc] = strdup(array3);
lpc++;
for(i=0;i<CMD_LENGTH;i++)
{
if(dc[i] == 34)
{
i++;
while(dc[i] != 34)
{
if(dc[i] == 32)
dc[i] = 33;
i++;
}
}
}
dc =strtok(NULL, white_space);
}
/*Loop through the remaining tokens, writing them to the struct. */
while ((dc = strtok(NULL, white_space)) != NULL) {
ifdef DEBUG
fprintf(stderr,”[%s]\n”,dc);
endif
result->argv = realloc((void *) result->argv, (lpc + 1) * sizeof(char )); result->argv[lpc] = strdup(dc); lpc++; } } /Set the final array element NULL. */
result->argv = realloc((void *) result->argv, (lpc + 1) * sizeof(char *));
result->argv[lpc] = NULL;
return;
} /*End of process_simple_cmd() */
/*
- This function parses the commands isolated from the command line string in
- other functions. It searches the string looking for input and output
- redirection characters. The simple commands found are sent to
- process_simple_comd(). The redirection information is stored in the result
- command structure.
* - Arguments :
- cmd – the command string to be processed.
- result – the command structure to store the results in.
* - Returns :
- None.
*
*/
void
process_cmd(char *cmd, command * result)
{
char *pc, *mc;
char *simple_cmd = NULL;
/*If no redirection found, then only a simple command present. */
if ((pc = index(cmd, ‘<‘)) == NULL) { if ((pc = index(cmd, ‘>’)) == NULL) {
process_simple_cmd(cmd, result);
result->redirect_in = NULL;
result->redirect_out = NULL;
}
else { /*Output Redirection in place */
if(index(pc,34) != NULL)//process quotes
{
process_simple_cmd(cmd,result);
result->redirect_out = NULL;
}
else
{
pc = strtok(cmd, “>”);
simple_cmd = strdup(pc);
pc = strtok(NULL, “\0”);
process_simple_cmd(simple_cmd, result);
result->redirect_out = strdup(pc);
}//end if else
}
}
else { /*Input Redirection */
if(index(pc,34) != NULL)//process quotes
{
process_simple_cmd(cmd,result);
result->redirect_out = NULL;
}
else
{
pc = strtok(cmd, “<“);
simple_cmd = strdup(pc);
pc = strtok(NULL, “\0”);
/*Output redirection may have been missed becuase input is checked
- first.*/
if ((mc = index(simple_cmd, ‘>’)) != NULL)
process_cmd(simple_cmd, result);
if ((mc = index(pc, ‘>’)) != NULL)
process_cmd(pc, result);
process_simple_cmd(simple_cmd, result);
result->redirect_in = strdup(pc);
}//end if else
}
free(simple_cmd);
return;
} /*End of process_cmd() */
/*
- This function processes the command line. It isolates tokens seperated by
- the ‘&’ or the ‘|’ character. The tokens are then passed on to be processed
- by other functions. Once the first token has been isolated this function is
- called recursivly to process the rest of the command line. Once the entire
- command line has been processed an array of command structures is created
- and returned.
* - Arguments :
- cmd – the command line to be processed.
* - Returns :
- An array of pointers to command structures.
*
*/
command **
process_cmd_line(char *cmd,int new)
{
char *rc, *mc;
char *rc_copy = NULL;
static command **cmd_line;
static int lc;
// nick nelissen added this 23/9/01
// ensures statics are null, when not recursively called
if(new==1)
{
lc=0;
cmd_line=NULL;
}//end if
/*
- Check for the existance of delimitors.
- If no delimitors exist, we only have one command on the command line.
- Otherwise process accordingly.
*/
if ((rc = index(cmd, ‘&’)) == NULL)
{
if ((rc = index(cmd, ‘|’)) == NULL)
{
//cut and pasted from above
if ((rc = index(cmd, ‘;’)) == NULL)
{
//cmd_line = realloc((void *) cmd_line, (lc + 1) * sizeof(command *));
cmd_line = realloc(cmd_line, (lc + 1) * sizeof(command *));
if(cmd_line==NULL)
{
exit(-1);
}//end if
cmd_line[lc] = malloc(sizeof(command));
if(cmd_line[lc]==NULL)
{
exit(-1);
}//end if
// nick added this to NULL the new struct
cmd_line[lc]->argv=NULL;
cmd_line[lc]->redirect_in=NULL;
cmd_line[lc]->redirect_out=NULL;
cmd_line[lc]->com_name=NULL;
cmd_line[lc]->pipe_to=0;
cmd_line[lc]->background=0;
process_cmd(cmd, cmd_line[lc]);
lc++;
}//end if 3
else
{
//this piece of code is copied from the code below, its
//cut and pasted from below, it
//handels ‘;’ the with the same code as & or |.
rc = strtok(cmd, “;”);
rc = strtok(NULL, “”); /*Get the second token out */
cmd_line = realloc((void *) cmd_line, (lc + 1) * sizeof(command *));
// nick changed this, same as nulling each element
//cmd_line[lc] = malloc(sizeof(command));
cmd_line[lc] = calloc(1,sizeof(command));
process_cmd(cmd, cmd_line[lc]);
//cmd_line[lc]->pipe_to = lc + 1;
lc++;
if (rc != NULL)
{
process_cmd_line(rc,0); /*Process the Second Token */
}//end if
}
}//end if 2
else
{ /*A ‘|’ was found */
rc = strtok(cmd, “|”);
rc = strtok(NULL, “”); /*Get the second token out */
cmd_line = realloc((void *) cmd_line, (lc + 1) * sizeof(command *));
// nick changed this, same as nulling each element
//cmd_line[lc] = malloc(sizeof(command));
cmd_line[lc] = calloc(1,sizeof(command));
process_cmd(cmd, cmd_line[lc]);
cmd_line[lc]->pipe_to = lc + 1;
lc++;
if (rc != NULL)
{
process_cmd_line(rc,0); /*Process the Second Token */
}//end if
}//end else
}// end if
else
{ /*A ‘&’ was found */
rc = strtok(cmd, “&”);
rc_copy = strdup(rc); /*Make a copy of the first token */
rc = strtok(NULL, “”); /*Get the second token out */
if ((mc = index(rc_copy, ‘|’)) != NULL)
{
process_cmd_line(rc_copy,0);
}//end if
else
{
cmd_line = realloc((void *) cmd_line, (lc + 1) * sizeof(command *));
// nick changed this
//cmd_line[lc] = malloc(sizeof(command));
cmd_line[lc] = calloc(1,sizeof(command));
process_cmd(cmd, cmd_line[lc]);
cmd_line[lc]->background = 1;
lc++;
}//end if
if (rc != NULL)
process_cmd_line(rc,0); /*Process the Second Token */
}//end if
cmd_line = realloc((void *) cmd_line, (lc + 1) * sizeof(command *));
cmd_line[lc] = NULL;
free(rc_copy);
return cmd_line;
} /*End of Process Cmd Line */
/*
- This function cleans up some of the dynamicly allocated memory. Each array
- element is visited, and the contained data is free’d before the entire
- structure is free’d.
* - Arguments :
- cmd – the array of pointers to command structures to be cleaned.
* - Returns :
- None.
*
*/
void
clean_up(command ** cmd)
{
int lpc = 0;
int ilpc = 0;
while (cmd[lpc] != NULL) {
ilpc = 0;
if (cmd[lpc]->com_name != NULL)
free(cmd[lpc]->com_name); /*Free Com_Name */
if (cmd[lpc]->argv != NULL) {
while (cmd[lpc]->argv[ilpc] != NULL) {
free(cmd[lpc]->argv[ilpc]); /*Free each pointer in Argv */
ilpc++;
}
free(cmd[lpc]->argv); /*Free Argv Itself */
}
if (cmd[lpc]->redirect_in != NULL)
free(cmd[lpc]->redirect_in); /*Free Redirect – In */
if (cmd[lpc]->redirect_out != NULL)
free(cmd[lpc]->redirect_out); /*Free Redirect – Out */
free(cmd[lpc]); /*Free the Command Structure */
lpc++;
}
free(cmd); /*Free the Array */
cmd = NULL;
return;
} /*End of clean_up() */
/*
- This function dumps the contents of the structure to stdout.
* - Arguments :
- c – the structure to be displayed.
- count – the array position of the structure.
* - Returns :
- None.
*
*/
void
dump_structure(command * c, int count)
{
int lc = 0;
printf(“—- Command(%d) —-\n”, count);
printf(“%s\n”, c->com_name);
if (c->argv != NULL) {
while (c->argv[lc] != NULL) {
printf(“+-> argv[%d] = %s\n”, lc, c->argv[lc]);
lc++;
}
}
printf(“Background = %d\n”, c->background);
printf(“Redirect Input = %s\n”, c->redirect_in);
printf(“Redirect Output = %s\n”, c->redirect_out);
printf(“Pipe to Command = %d\n\n”, c->pipe_to);
return;
} /*End of dump_structure() */
/*
- This function dumps the contents of the structure to stdout in a human
- readable format..
* - Arguments :
- c – the structure to be displayed.
- count – the array position of the structure.
* - Returns :
- None.
*
*/
void
print_human_readable(command * c, int count)
{
int lc = 1;
printf(“Program : %s\n”, c->com_name);
if (c->argv != NULL) {
printf(“Parameters : “);
while (c->argv[lc] != NULL) {
printf(“%s “, c->argv[lc]);
lc++;
}
printf(“\n”);
}
if (c->background == 1)
printf(“Execution in Background.\n”);
if (c->redirect_in != NULL)
printf(“Redirect Input from %s.\n”, c->redirect_in);
if (c->redirect_out != NULL)
printf(“Redirect Output to %s.\n”, c->redirect_out);
if (c->pipe_to != 0)
printf(“Pipe Output to Command# %d\n”, c->pipe_to);
printf(“\n\n”);
return;
} /*End of print_human_readable() */
/
parser.h – description
——————-
begin : Fri Oct 4 2002
copyright : (C) 2002 by C Brookes
email :
/
/*
- *
- This program is free software; you can redistribute it and/or modify *
- it under the terms of the GNU General Public License as published by *
- the Free Software Foundation; either version 2 of the License, or *
- (at your option) any later version. *
- *
*/
ifndef _PARSER_H
define _PARSER_H
/*
- Parser.h
- Data structures and various defines for parser.c
- Author : Michael Roberts mroberts@it.net.au
- Last Update : 15/07/01
*/
include
include
include
/The length of the command line./
define CMD_LENGTH 256
/Whitespaces that are searched for/
// nick modified this
//static const char white_space[2] = { (char) 0x20, (char) 0x09 };
static const char white_space[3] = { (char) 0x20, (char) 0x09, (char) 0x00 };
/The Structure we create for the commands./
typedef struct Command_struct
{
char *com_name;
char **argv;
int background;
char *redirect_in;
char redirect_out; int pipe_to; } command; / Function prototypes added by Nick Nelissen 11/9/2001 */
command ** process_cmd_line(char *cmd,int);
void process_cmd(char *cmd, command * result);
void process_simple_cmd(char *cmd, command * result);
void clean_up(command ** cmd);
void clean_up(command ** cmd);
void clean_up(command ** cmd);
endif
References:
- Page 10 line 38: www-instruct.wccnet.org/~chassel/linux275/ClassNotes/process/myshell.htm
- Page 10 line 44: www.cs.bsu.edu/homepages/dlsills/davis_myshell.html
- Page 12 line 14: Unix System Programming Haviland pg 156
- Page 013 line 12: www-instruct.wccnet.org/~chassel/linux275/ClassNotes/process/myshell.htm
- Page 013 line 31: www.umsl.edu/~s1002145/msdos.html
- Page 14 line 9: www.umsl.edu/~s1002145/msdos.html
- Page 14 Line 37: Unix System Programming Haviland pg 113