Mihika Pradhan: myp33
For this project, I started by creating a loop to read commands, whether they were given by standard input or through a file.Once each complete command was read, it was split up into tokens, with the first serving as the program name (unless it was then or else), and the rest serving as arguments (if not a redirection file). I created a struct that would hold a pointer to the name of the program, pointers to the redirection files if there were any, and a pointer to pointers storing the arguments. If there was a pipe symbol, my function would call itself and store the second half of the command in a different struct. Before being pushed into the argument list, every token is also checked for wildcards-- if there are asterisks present in the token, the wildcard is expanded and those tokens are pushed into the argument list instead.
I used test.c to test my structs and the arraylist, making sure that all the values were stored properly and could be accessed as they were needed. I then had a function that checked for pipes, if necessary, and adjusted input and output based on that. Then I had a separate function that would open redirection files if needed (and change the arguments in the struct if there was an input file provided to the tokens in the file), compare the program name with built ins, check for a slash, and run accordingly. I used fork() to execute the commands, in case there were different inputs or outputs provided for that command that did not apply to the program as a whole.
I tested as I went along--when reading commands, I made sure that the commands were being read in their entirety by printing them after they were completed. I tested the struct using test.c and making sure that the structs were storing the information properly by printing the values once they were inserted. I coded each command one at a time and tested as many scenarios as I could think of per command. For example, for exit, I tested scenarios in which there were arguments given and no arguments. For which, I tested programs in all three directories. I used foo.c and bar.c to assist in testing things like pipes and wildcards, to make sure that the appropriate things were being printed out when input was redirected and wildcards were present, etc. I made sure to test wildcards in different tokens, including after pipes. I tested redirection for input files and output, as well as piping files that I had created along with programs I searched the directories for. I tested in different orders, to make sure that there was nothing preventing commands from executing after the last one had (for example, since I used a global int to store whether or not there was a pipe necessary, I had to test commands without pipes before one with a pipe, following it with another command without a pipe). I tested scenarios in which the programs failed, as well.
I did have some issues with memory leaking in certain places; however, despite these memory leaks, the program is able to execute commands as called.
To execute, you can call make and then ./mysh for interactive mode, or ./mysh myscript.sh or cat myscript.sh | ./mysh for batch mode with a script I created to test certain commands.