#include #include struct command_line { char **tokens; bool stdout_pipe; char *stdout_file; }; void execute_pipeline(struct command_line *cmds) { /** * TODO: design an algorithm that sets up a pipeline piece by piece. * Solutions will probably either iterate over the pieces of the pipeline or * work recursively. Imagine you have three commands in a pipeline: * * - cat * - tr * - sed * * Use 'stdout_pipe' to determine when you've reached the last command in * the pipeline, and 'stdout_file' to decide whether the final result gets * written to a file or the terminal. * * If we aren't at the last command, then we need to set up a pipe for the * current command's output to go into. For example, let's say our command * is `cat file.txt`. We will create a pipe and have the stdout of the * command directed to the pipe. Before running the next command, we'll set * up the stdin of the next process to come from the pipe, and * execute_pipeline will run whatever command comes next (for instance, * `tr '[:upper:]' '[:lower:]'`). * * Here's some pseudocode to help: * * create a new pipe * fork a new process * if pid is the child: * dup2 stdout to pipe[1] * close pipe[0] * execvp the command * if pid is the parent: * dup2 stdin to pipe[0] * close pipe[1] * move on to the next command in the pipeline * * The special case here is when there are no more commands left. In that * case, you can simply execvp the command (no need to create another pipe). * If you created a handler process in main(), then it will be replaced by * this last call to execvp. */ } int main(int argc, char *argv[]) { char *input_file = NULL; char *output_file = NULL; if (argc < 2 || argc > 3) { printf("Usage: %s file-to-leetify [output-file]\n", argv[0]); return 1; } input_file = argv[1]; if (argc == 3) { output_file = argv[2]; } /* TODO: Next steps: * finish setting up the array of command_line structs * fork() to create a 'handler' process that will call execute_pipeline * wait for the handler to finish */ // TODO: These commands aren't quite finished... char *command1[] = { "cat", "file.txt", (char *) NULL }; char *command2[] = { "tr", "[:upper:]", "[:lower:]", (char *) NULL }; char *command3[] = { "sed", "s|CATS|MEOW|g", (char *) NULL }; struct command_line cmds[3] = { 0 }; cmds[0].tokens = command1; cmds[0].stdout_pipe = true; cmds[0].stdout_file = NULL; cmds[1].tokens = command2; /* TODO: Finish filling these in ... */ cmds[2].stdout_pipe = false; /* Last command so set stdout_pipe = false */ execute_pipeline(cmds); return 0; }