CS 537 - Spring 2007
Programming Assignment 1
Frequently Asked Questions

Last modified Tue Jan 16 14:33:41 CST 2007
Q1:
Do I have to do something special for quotes on the command line? For example, when I type the command
    echo "some                          spaces"
should the the argv passed to exec() contain two words or three, and should the output be
    some                          spaces
or
    "some spaces"

A:
You do not have to give any special treatment to quotes. You can consider a quote to be a non-space character like any other, and only spaces serve to separate command-line arguments. Thus the second output above is correct.

See also Q2, Q3


Q2:
Do I have to implement shell "wild-card" characters such as "*"? The command
    ls *
produces the output
    ls: *: No such file or directory

A:
No, you don't have to implement shell "wild-card" characters (or any other special feature other than "&"). The sample output above is correct.

Q3:
Why do I have to break up each command into words? There is a version of Runtime.exec() that takes a single string and it seems to work fine.

A:
You may use this version of exec() if you like. However, one warning: An empty command line should do nothing except print another prompt. The same is true for a line containing nothing but spaces and tabs. The method Runtime.exec(String) may not do the right thing in these cases.

Q4:
My program terminates fine if I use the exit command. Should there be any other way to terminate it (short of killing it)?

A:
The program should also terminate on end-of-file (EOF). If the input comes from a file, as in
    java P1 < testfile
EOF means just what the name implies: the end of the file. If the input comes directly from the keyboard, you can simulate an EOF condition by typing control-D (type 'd' while holding down the control key). On Windows, use control-Z instead. When it detects eof-of-file, readLine() returns null (that's the null-pointer value null not a string of length zero). Your program should not terminate on an empty command line; instead it should do nothing but print another prompt. See Q3.

Q5:
When I type the command "cat" to my program, it just hangs. What's wrong?

A:
When the "cat" command is called with no arguments, it copies standard input to standard output. Since you don't use getOutputStream() to pass data to the standard input of a process, it will just sit there forever waiting for input. The assignment specifically says that you don't have to deal with the standard input of the processes you create. Thus this behavior is not a bug but a "feature"! Similarly, "more" (or "less") will not do anything useful.

Q6:
The cd command doesn't seem to work. What am I doing wrong?

A:
The current working directory (cwd) is a property of a process in Unix (or Windows). You are creating a Process object to run the command. The cd command is indeed changing the cwd of the process, but when the command terminates, the process goes away and there is no effect on your main shell program. The reason cd works like it does in a "real" shell is that the shell treats it specially. You are not required to implement this feature.

Q7:
I am unclear about the instructions for reading the normal output and the error output from the commands that are executed. You said that we need to create thread for each of these (at least two per command). I have called the corresponding functions p.getInputStream() and p.getErrorStream() (p being the process created to execute the command) without creating any extra threads, and then simply wait for p to finish by calling p.waitFor(), and then echo the corresponding streams. This seems to work fine. Is there some reason why we should not be doing it this way or is this OK? Please let me know.

A:
You are refusing to read the command's output until it terminates, but it cannot terminate until it finishes writing all of its output, and it cannot finish writing all of its output until you read it. This situation is called deadlock; we will be studying it in depth later in the semester.

If you try to echo the output and error streams before waiting for the process to terminate, you have to read from one before the other. Suppose you first read from the error stream and the command you're running is trying to write to its output stream. Your thread will be blocked waiting to read data from the error stream while there's nothing there to read. Your read() call cannot return null (meaning there's nothing more to read) until the command finishes, since there's no way to guarantee there will be no error output until the command finishes running. But the command cannot terminate until it successfully writes its output to its output stream, and it cannot do that until you read it. Once again, you have deadlock. Of course, if you decide to read from the output stream first, you will deadlock with a command that wants to write a lot of data to its error stream.

The reason your tests seem to work ok is that there is a certain amount of buffering built into the streams (that is, memory arrays where the data sits after the command has written it but before your program reads it). In your test, the command writes its output into the stream buffers and terminates; then your program notices it has terminated, reads the data from the buffers and echos it. On some systems, the amount of buffering is limited to a few thousand bytes. On Linux, it is nearly unlimited.


Q8:
What should our input prompt look like?

A:
The prompt can be any string containing at least one non-blank character. You probably want to use something different from your real shell to avoid getting confused. One suggestion is "$ ".

Q9:
What should the name of the main class be for project 1?

A:
The main class (the one with the main method) should be named P1. In other words, it should be in a file named

    P1.java
which is compiled by the command

    javac P1.java
and run by the command

    java P1
Note also (see Q4 above) that it should be possible to run you program taking the “interactive” input from a file rather than the keyboard, with a command such as

    java P1 < testfile