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. Encapsulate data structures with functions. 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, call 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 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.
(Recommended) Read each input line using the fgets() function.
(Recommended) Implement your lexical analysis phase as a deterministic finite state automaton.
(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 |
one |
one |
123 |
123 |
one123 |
one123 |
123one |
123one |
@#$%^&*() |
@#$%^&*() |
' |
' |
one two |
one two |
one two |
one two |
one two |
one two |
one > |
one > |
one> |
one > |
>one |
> one |
"one" |
one |
">" |
> (an ordinary token) |
"one two" |
one two |
one"two" |
onetwo |
"one"two |
onetwo |
"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 command 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 command 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:
INPUT LINE | VALID/INVALID |
cat |
Valid |
cat file1 |
Valid |
cat < file1 |
Valid |
cat > file1 |
Valid |
cat < file1 > file2 |
Valid |
cat > file1 < file2 |
Valid |
cat file1 > file2 |
Valid |
cat > file2 file1 |
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 > file2 > file3 |
Invalid: Multiple redirection of standard output |
cat < file1 < file2 |
Invalid: Multiple redirection of standard input |
(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.
(Required) Execute the history command in a child process (alias subshell) so its standard output can be redirected.
(Required) Do not store an input line in the history list if it consists entirely of whitespace characters.
(Required) After expanding an input line containing !commandprefix, print the expanded input line before executing it.
(Required) Match !commandprefix with the most recently executed command that has commandprefix as a prefix.
(Required) Consider all characters that occur in the input line between an exclamation point and a terminator character to be the commandprefix which should be expanded. The terminator characters are space, tab, newline, null, less-than, and greater-than.
(Required) When expanding !commandprefix, consider the double quote character to be an ordinary character, devoid of any special meaning.
(Required) When expanding !commandprefix, if commandprefix is empty, then expand it to nothing.
(Required) Handle multiple instances of !commandprefix within the input line.
(Required) If an input line containing !commandprefix cannot be expanded (that is, if no previous command has commandprefix as its prefix), then print an error message to stderr, and do not store that input line in the history list.
(Recommended) Test your history mechanism using a variety of command sequences involving use of the exclamation point, double quote, less-than, and greater-than characters. For example, make sure it handles this sequence of input lines properly:
INPUT LINE | INPUT LINE AFTER EXPANSION |
echo one two |
echo one two |
!echo |
echo one two |
echo one two |
echo one two |
!ech>junk |
echo one two>junk |
!ec |
echo one two>junk |
echo one two |
echo one two |
!ec three !e four |
echo one two three echo one two four |
echo one two |
echo one two |
echo three!ec four |
echo threeecho one two four |
echo one two |
echo one two |
!"ech" |
Error - Event not found |
!ech"three" |
Error - Event not found |
!ech "!ech three" |
echo one two "echo one two three" |
! echo |
echo |
! |
|