CS330 Project (Fall 2005)
Part 1--worth 8% (Due November 9)
Design and implement a "myshell" command interpreter to provide the following commands:
(For part 1, you will *NOT* use exec to execute utility programs)
- EXIT: stop the command interpreter
- HISTORY: list the commands that have been entered in this session
- !n: re-execute a command from the history list, e.g., !6 causes the 6th command in the list to be executed again
- NEWNAME: define a new name (alias) for another command; for example, you
might establish move as an alternative name for mv
- READNEWNAMES: read the names and definitions of all "new names" stored in
the specified file and add them to the current set of "new names"
- SAVENEWNAMES: store all currently defined "new names" and their
definitions in the specified file.
- LSL: list detailed information about all files in the current directory,
perhaps in the same format as ls -l does.
- In addition, your prompt should be set to "mysh." concatenated with the current working directory.
For example:
mysh./home/venus2/nova/330>
Hint: the present working directory can be found to a call such as the following:
getenv("PWD")
Click here for more submission and marking scheme details
Part 2--worth 7%(Due December 2)
Modify the myshell program that you produced in assignment #1 to include
the following features:
- use fork/execvp/wait system calls to
execute utility programs (to expand your code from the original commands).
- background execution: if a % appears at the end of a command, it should be
executed in the background. Thus,
sleep 60 %
should start a sleep process running in the background for 60
seconds. In the meantime, the myshell process should continue performing
other commands for the user. To implement this feature, the myshell
process should not wait for the child to complete. This feature is similar
to tcsh's &. An % should be ignored if the shell is in LAUNCH mode (see
below).
- LAUNCH mode: if the command LAUNCH is entered, all subsequent commands
will automatically be started running in the background. The LAUNCH
command should report and error if the shell is already in LAUNCH mode
- ORDINARY mod: if the command ORDINARY is entered, the shell will leave
launch mode and return to ORDINARY mode. That is, background execution is
only employed where a % is given. The ORDINARY command should be ignored
if the shell is not in LAUNCH mode.
- MODE command: reports whether the shell is in LAUNCH mode or ORDINARY mode.
- SLEEP command: implements a built-in feature to your shell that allows the
suspending of execution for a specified number of seconds. It should work
the same as the UNIX sleep command (man 1 sleep). It is easily implemented
with the sleep library function
- piping between two commands--if commands are separated by a colon
(:). This facility is similar to Tcsh's |. Implement it by creating two
processes and changing the object descriptors (file descriptors) for
each. You should make the stdout of the first command equal to the pipe's
input and the stdin of the second command equal to the pipe's output.
Click here for more submission and marking scheme details
The following are meant as suggestions to aid you in completing this project.
To start off with, you will need a way of reading from the keyboard. Once the user types a newline character ('\n'), you can process the entire line. You can do that using the read
system call. The following code might help you get started:
#include <cstdio> //for printf
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/stat.h> //needed to get file info
#include <pwd.h> //needed for getting user name
#include <grp.h> //needed for getting group id
#include <time.h> //needed for converting time
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <wait.h> //needed for wait
using namespace std;
#define MAX_ARGS_PER_CMD 10
#define MAX_ARG_SIZE 256
int parseBuffer (char *buf, char **target, int maxArgs);
int main (int argc, char* argv[])
{
char *myArgv[MAX_ARGS_PER_CMD]; //to be used with parseBuffer
char buffer[MAX_ARG_SIZE]; //one line of input
int numChar=0;
int numArgs=0;
char prompt[130];
strcpy(prompt, "mysh.");
write(1, prompt, strlen(prompt));
while (read(0, &buffer[numChar], 1)!=0)
{
if (buffer[numChar]=='\n')
{
buffer[numChar]='\0';
write(1, buffer, numChar); //just display the line that was typed --for debugging
//separate the command line into all the arguments by calling parseBuffer--this is useful for Part 2
//check for "EXIT". If typed, exit loop
//else process the command
write(1,"\n", 1);
numChar=-1; //start at the beginning of the buffer
write(1, prompt,strlen(prompt));
}
numChar ++;
}
}
int parseBuffer(char *buf, char **target, int maxArgs)
{
int ctr=0;
char * temp = strtok(buf, " ");
while(temp !=NULL)
{
if (ctr >= maxArgs)
{
return -1;
}
target[ctr] = temp;
++ ctr;
temp = strtok (NULL, " ");
}
target[ctr]=NULL;
return ctr;
}
Some commands that may come in handy. You may find other solutions:
String functions
- strtok
- strcat or strncat
- strcmp or strncmp
- strcpy or strncpy
- strlen
For turning id numbers into strings and the ctime into a string:
The following code is useful for reading the files in the current directory
#include <sys/types.h>
#include <sys/dir.h>
#include <cstdio>
using namespace std;
main()
{
DIR *dirp;
struct dirent *direntp;
dirp = opendir( "." );
while ( (direntp = readdir( dirp )) != NULL )
(void)printf( "%s\n", direntp->d_name );
closedir( dirp );
return (0);
}
Another way that you can get all of the entries in a
directory is by using getdents.
Our system administrator, Robert Cowles, has provided the following
code