Programming Assignment 4

Due date Wednesday, Oct 13 at 11:59PM

Take the shell code that you wrote for assignment 2 and add pipes, so that a user can two or more processes together. The user has the option of redirection standard input (for the first process) to read from a file rather than from the keyboard, and/or redirecting standard output (for the last process) to a file instead of to the terminal.

The user can chain any number of processes together with pipes. In all cases the output of a process is redirected as the input of the next process. Here is an example.

Proc1 | Proc2 | Proc3

Your shell would call fork three times. The first child would exec Proc1, the second child would exec Proc2, and the third child would exec Proc3. The output of Proc1 would be piped as the input of Proc2; and the output of Proc2 would be piped as the input of Proc3.

In order to find the executables, your program should search an environment variable called SEARCHPATH. This will consist of a list of directories, delimited by dollar signs. Your program should search the first directory, then the second, and so on, looking for an executable file.

To set an environment variable from the shell use the shell command export. Here is an example:
export SEARCHPATH=/usr/bin$/usr/local/bin$.
Note that there are no spaces on either side of the = operator. You should execute this command prior to invoking your shell.

To access an environment variable from inside a program on Unix, use the library function getenv. Here is the function prototype

   #include <stdlib.h>
   char *getenv(const char *name);
Type man getenv to get more information.

Each process can take up to ten arguments. Here is a more complex command line:

proc1 arg1 arg2 < infile | proc2 arg1 arg2 arg3 | proc3 arg1 > outfile

As before, I will do the hard part for you. The function

int ParseCommandLine(char line[], struct CommandData *data)

takes a command line as an argument and populates a CommandData structure. The function returns 1 if it was able to successfully parse the line, and zero if there was some kind of error in the line. The structure of CommandData is more complex this time. Here it is.

struct Command {
  char *command;
  char *args[11];
  int numargs;
};

struct CommandData {
  struct Command TheCommands[20];  /* the commands to be
          executed.  TheCommands[0] is the first command
          to be executed.  Its output is piped to
          TheCommands[1], etc. */
  int numcommands; /* the number of commands in the above array */
  char *infile;   /* the file for input redirection, NULL if none */
  char *outfile;  /* the file for output redirection, NULL if none */
  int  background;  /* 0 if process is to run in foreground, 1 if in background */
};
Here is a link to the header file which defines all of this code

Here is a link to the file that I used to test this function. It may help you to understand how this works (or you can choose to ignore it). At the prompt, enter a command string, and it will parse it for you, displaying the values. This runs in an infinite loop; to get out, enter the command quit