The following are implementation requirements and recommendations for ish:
(Required) Write your program so it is modular. Create small functions, each of which does a single well-defined job. Define interfaces and implementations, thus splitting your program into multiple files in the standard way. Define either abstract objects or abstract data types as appropriate. Doing so will earn you a better grade. More fundamentally, doing so will help you to write a better program quicker.
(Recommended) See the web page http://www.opengroup.org/onlinepubs/7908799/xsh/unistd.h.html for excellent documentation on the UNIX system calls. You may find that documentation more convenient than the "man" pages.
(Required) Use calls to the assert macro to validate the parameters of every function in your program.
(Recommended) Use the DynArray ADT (from early precepts). The source code is available through the course web pages.
(Required) Print all error messages to standard error, not to standard output.
(Required) After a failed system call, use the perror standard function to print an appropriate error message to standard error.
(Required) Make sure that your ish interprets commands from the .ishrc file when it is first launched. We will test your ish by repeatedly copying command sequences to the .ishrc file and launching your ish. If your program does not interpret commands from that file, then it will fail all of our tests. In that unfortunate circumstance, the grade would be very poor.
(Required) Make sure that your ish looks for the .ishrc file in the HOME directory, not in the current directory. Also make sure that your ish works properly if the .ishrc file does not exist, or is not readable.
(Required) Your ish should print the commands from .ishrc. That is, immediately after your ish reads a command from the .ishrc file, it should print that command to standard output. In that manner ish should generate a transcript that shows each command of .ishrc, followed by the output that results from executing that command. If your program does not print the commands of .ishrc to standard output, then it will be difficult to interpret the transcript. In that unfortunate circumstance, the grade would be penalized.
(Required) Your ish should not print the commands from standard input. That is, when your ish reads a command from standard input, it should not print that command to standard output.
(Required) The source code declarations of the setenv and unsetenv UNIX system calls are not included in any system header file. Instead they are available in the header file /u/cos217/Assignment6/setenv.h. You should copy that file to your working directory and #include it into your source code as appropriate.
(Recommended) Read each input line using the fgets function.
(Recommended) Implement your lexical analysis phase as a deterministic finite state automaton (FSA) in the manner shown in precepts.
(Recommended) Create some temporary code that prints the token list created by the lexical analysis phase. Do not proceed to subsequent phases until you test your lexical analysis phase thoroughly.
(Recommended) Test your lexical analysis phase by making sure that it handles these example input lines properly:
|INPUT LINE||TOKEN ARRAY|
|">"||> (an ordinary token)|
|"one two"||one two|
|"one||ERROR - unmatched quote|
|one"two||ERROR - unmatched quote|
(Required) Make sure that your lexical analysis phase represents tokens so that the difference between quoted and unquoted special characters is adequately captured. For example, these two commands are very different, and that difference must be captured at the lexical analysis phase:
echo one > two echo one ">" two
(Recommended) Do as much validation of the pipeline as you can at the syntactic analysis phase. The more error checking you do in the syntactic analysis phase, the less must be done during the (more complicated) execution phase.
(Recommended) Create some temporary code that prints the pipeline created by the syntactic analysis phase. Do not proceed to subsequent phases until you test your syntactic analysis phase thoroughly.
(Recommended) Test your syntactic analysis phase by making sure that it handles these valid and invalid example input lines properly:
|cat < file1||Valid|
|cat > file1||Valid|
|cat < file1 > file2||Valid|
|cat > file1 < file2||Valid|
|cat file1 > file2||Valid|
|cat > file2 file1||Valid|
|cat | sort||Valid|
|cat | cat | cat | sort||Valid|
|cat < file1 | sort > file2||Valid|
|cat < file1 | cat | cat | sort > file2||Valid|
|< file1||Invalid: Missing command name|
|cat file1 <||Invalid: Standard input redirection without file name|
|cat file1 >||Invalid: Standard output redirection without file name|
|cat file1 |||Invalid: Pipe symbol without following command|
|cat file1 > file2 > file3||Invalid: Multiple redirection of standard output|
|cat < file1 < file2||Invalid: Multiple redirection of standard input|
|cat file1 | cat | sort < file2||Invalid: Only first pipeline command can redirect stdin|
|cat file1 | cat < file2 | sort||Invalid: Only first pipeline command can redirect stdin|
|cat file1 > file2 | cat | sort||Invalid: Only last pipeline command can redirect stdout|
|cat file1 | cat > file2 | sort||Invalid: Only last pipeline command can redirect stdout|
(Required) Call fflush(NULL) before each call of fork to clear all I/O buffers.
(Required) Use the setenv UNIX system call to implement the setenv shell built-in command.
(Required) Use the unsetenv UNIX system call to implement the unsetenv shell built-in command.
(Required) Use the chdir UNIX system call to implement the cd shell built-in command.
(Recommended) If you have trouble with the pipeline logic, then temporarily back away from ish and write a simpler test program. Specifically, write a program that, in a hardcoded manner, executes the pipeline ls | sort | more. You may find it straightforward to generalize that program to create the pipeline handling code of ish.
(Required) Execute the history command in a child process (alias subshell) so its standard output can be redirected, and so it can be part of a pipeline.