Princeton University
COS 217: Introduction to Programming Systems

Assignment 6: Supplementary Information

The following are implementation requirements and recommendations for ish:

General

(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) After printing to standard output, immediately flush the standard output stream by calling fflush(stdout). Doing so eliminates complications with output buffering in the presence of concurrent processes.

(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.

Building

(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/cs217/Assignment6/setenv.h. You should copy that file to your working directory and #include it into your source code as appropriate.

(Required) The object code definitions of the setenv and unsetenv UNIX system calls are not included in the standard libc.a library. Instead they are available in the library /u/cs217/Assignment6/libsetenv.a. To use that library, you should copy it to your working directory, and append "-L. -lsetenv" to the end of each gcc command that links your code to produce an executable file. (Pages 88-89 of our "GNU Software" textbook describe the meaning of the -L and -l options to gcc.)

Lexical Analysis

(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
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

Syntactic Analysis

(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:

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
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

Execution

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

(Required) Use the umask system call to determine the permissions of a file that is created via redirection of standard output. Here's a sequence of statements that indicates how:

/* Fetch the umask, and set it to 0 */
iUmask = umask(0);
/* Reset the umask to its original value. */
umask(iUmask);

/* Compute the new file's permissions as the complement
of the umask, but without execute permission. */
iPermission = (~iUmask) & 0666;

(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.

History (for extra credit)

(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.