I'm supposed to write an interpreter program which is more like a command prompt. This is some background info:
General flow of basic interpreter
1. Prompt for user request.
2. Carry out the user request.
3. Unless user terminates the program, go to step 1.
Run a command. Format:
R command_path [arg1 to arg4]
//a single character ‘R’ which stands for 'Run', followed by the path of the command
//the user can supply up to 4 command line arguments
Behavior:
a. If command exist, run the command in a child process with the supplied
command line arguments
Wait until the child process is done
b. Else print error message “XXXX not found”, where XXXX is the user
entered command
E.g.
YWIMC > R /bin/ls
a.out ex2.c ...... //output from the “ls” command
YWIMC > R /bin/ls –l //same as executing “ls –l”
total 144
-rwx------ 1 sooyj compsc 8548 Aug 13 12:06 a.out
-rwx------ 1 sooyj compsc 6388 Aug 13 11:36 alarmClock
.................... //other files not shown
the idea i have so far is, read in file path, read in arguments, use execv(filePath, args). however, i can't get the loop and the syntax right.
while(scanf("%s", args[i]) !=0) { //read in arguments
i++;
}
execv(filePath,args);
this reads an infinite number of arguments. as i said i can't get the syntax right. processing strings in C is such a pain :(
Re-edited. This is my current code which is rather incomplete
#include <stdio.h>
#include <fcntl.h> //For stat()
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> //for fork(), wait()
int main()
{
char request, filePath[100];
int result, pathExist, childID, status;
struct stat buf;
//read user input
printf("YWIMC > ");
scanf("%c", &request);
while (request != 'Q'){ //if 'Q' then just exit program
// Handle 'R' request
scanf("%s", &filePath); //Read the filePath/program name
pathExist = stat(filePath, &buf);
if(pathExist < 0) {
printf("%s not found\n", filePath);
}
else {
result = fork();
if(result != 0) { //Parent Code
childID = wait(&status);
}
else { //Child Code
if(strcmp(filePath, "/bin/ls") == 0) {
execl("/bin/ls", "ls", NULL); //change to execv
} //with the use of a 2D
//string array
else { //same for this
execl(filePath, NULL);
}
return 256;
}
}
fflush(stdin); //remove all left over inputs
printf("YWIMC > ");
scanf("%c", &request);
}
printf("Goodbye!\n");
return 0;
}
OK, I think I finally understand what it is you want to do. To create your
YWIMC
interpreter environment and be able to handle bothcommand not found
and errors in the execution with the command passed toexecv
as well as returning to theYWIMC
after a successful command, you have tofork
the call toexecv
to a separate process to preventexecv
from terminating the program.Basically, you create the
YWIMC
shell with an outerwhile
loop displaying the prompt and reading the command line (cmdline
) on each iteration. Within the loop, the easiest way to separate the command line is withstrtok
orstrsep
(strtok
) used below. You can make that process simple by callingstrtok
in afor
loop:Note:
strtok
modifies the original string, so you must make a copy of the string to be able to provide theerror
message containing the original command line.If the users enters a request
R
as the first token and it has at least one additional argument, youfork
the process. In the child (pid == 0
) you pass the proper/path/to/command
and arguments toexecv
. The easiest way to pass the proper command and arguments is to create a pointerargs
that points to the second element ofcmdline
(so thatR
is effectively discarded from the array passed toexecv
). You also need to provide a way for the child process to exit in the event a bad command is passed toexecv
(otherwise the user will wonder why they must enterq
twice to exit after a bad command is passed.)At that point, it is up to
execv
to execute the command, or fail with an error provided on failure. When the users enterq
the shell will need to free all memory allocated bystrdup
and then exit.Try the following and let me know if I finally understood what you were attempting to do. Let me know if you have any questions.
Compile
or to compile with debug output enabled:
Use/Output