Princeton University
COS 217: Introduction to Programming Systems

Assignment 7: Supplementary Information

The following are implementation requirements and recommendations for your shell program:


General

(Required) Your program should be modular at the function level. Define small functions, each of which does a single well-defined job.

(Required) Your program should be modular at the source code file level. Define interfaces and implementations, thus splitting your program into multiple files. Define stateless modules, abstract objects, or abstract data types as appropriate. Encapsulate data structures with functions.

(Recommended) Your program may use the DynArray ADT (from early precepts). The source code is available through the course web pages, and also in the /u/cos217/Assignment7 directory on hats.

(Required) Your program should interpret commands from the .ishrc file when it is first launched. We will test your program by repeatedly copying command sequences to the .ishrc file and launching your program. 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 penalized substantially.

(Required) Your program should look for the .ishrc file in the HOME directory, not in the working directory.

(Required) Your program should work properly if the .ishrc file does not exist or is not readable. It is not an error for the .ishrc file to not exist or to be unreadable.

(Required) Your program should print the commands from .ishrc. That is, immediately after your program reads a command from the .ishrc file, it should print its "% " prompt and that command to the standard output stream. In that manner your program 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 the standard output stream, then it will be difficult to interpret the transcript. In that unfortunate circumstance, the grade would be penalized substantially.

(Required) Your program should not print the commands from the standard input stream. That is, when your program reads a command from the standard input stream, it should not print that command to the standard output stream.


Error Handling

(Required) Your program should detect and report each programmer error via a call of the assert macro. A programmer error is one that could not be caused by user input.

(Required) Your program should call the assert macro to validate the parameters of every function in your program, especially the non-static ones.

(Required) Your program should detect each user error via an if statement, and should report each user error via a descriptive error message. A user error is one that could be caused by user input.

(Required) Your program should check the result of each attempt to dynamically allocate memory. It should recover from dynamic memory allocation failures as gracefully as possible.

(Required) Your program should print error messages to the standard error stream, not to the standard output stream.

(Required) Your program's error messages should begin with programName:, where programName is your program's argv[0]. Note that the name of your program is not necessarily "ish"; the user might have renamed the executable binary file to something other than "ish".

(Required) After a failed call of a function that sets the errno variable, your program should call the perror or strerror function to print an appropriate error message.


Lexical Analysis

(Recommended) Your program should read each input line by calling the fgets function.

(Recommended) Implement your lexical analyzer as a deterministic finite state automaton.

(Required) Your program should call the isspace function to identify white-space characters.

(Recommended) Create some temporary code that prints the token list created by your lexical analyzer. Do not proceed to subsequent phases until you test your lexical analyzer thoroughly.

(Recommended) Test your lexical analyzer 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

(Recommended) Your program's lexical analyzer should represent 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 should be captured at the lexical analysis phase:

echo one > two
echo one ">" two

Syntactic Analysis

(Recommended) Your program should do as much validation of the command as possible at the syntactic analysis phase. The more error checking you do during 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 your syntactic analyzer. Do not proceed to subsequent phases until you test your syntactic analyzer thoroughly.

(Recommended) Test your syntactic analyzer 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

Execution

(Required) Your program should call fflush(NULL) before each call of fork to clear all I/O buffers.

(Required) Your program should call the setenv function to implement the setenv shell built-in command.

(Required) Your program should call the unsetenv function to implement the unsetenv shell built-in command.

(Required) Your program should call the chdir function to implement the cd shell built-in command.

(Required) Your program should call exit(0) to implement the exit shell built-in command. Or, implement the exit command by returning 0 from the program's main function.

Signal Handling

(Required) Your program should call the signal function to install signal handlers.

(Required) Your program should call the alarm function to control handling of SIGQUIT signals.

(Required) Your program should use the SIG_IGN and SIG_DFL arguments to the signal function, as appropriate.

(Required) Your program should call the sigprocmask function near the beginning of the main function to make sure that SIGINT, SIGQUIT, and SIGALRM signals are not blocked.