JShell
(Andrew Van Kirk)
Version
1.0
A Unix-Like Shell
Written in Java
Programmer’s
Guide
Welcome to Jshell! This is
the Programmer’s Guide. If you like
running programs a lot, you may want the User's Guide. This is where you learn how to program
JShell.
JShell Structure
The JShell Program can be
broken up into three main parts:
JShell: This is the .class file
that is actually run to start the program.
It handles user input and runs the commands, as well as does some basic
error handling.
JShellParser: This class parses the user input line.
Because there is only one instance of this parser instantiated by
JShell, all of its fields are private.
This is VERY important, because JShellParser not only holds the map of Strings
to Command classes, but also holds such data as the current directory and the
map of environment variables. Though
this may seem awkward, it really works out quite elegantly. For example, because all commends that deal
with traversing the directory structure, such as “cd” and “pwd” are constructed
with the same directory stack from JShellParser, and change to the current directory
by one command changes the current directory in all the other commands.
Commands: The
heart and soul of JShell. Each command
runs itself and returns its output, if any, on the StringBuffer that it is
passed when method runCommand(StringBuffer) is invoked. Every command inherits from Command, but
there is also some deeper inheritance. See the Class
Documentation for a clear picture of this inheritance.
Adding to JShell
There are several rules that
should be followed when adding to JShell
1) DO NOT modify JShell.java. It is not necessary unless major
modifications are being made to program flow.
2) Add only one line to JShellParser, in method void
putCommands(), that adds your command and the corresponding user input string
to the map of commands.
3) Rule 2 may be broken if you are implementing a new series
of command that required the same data to be accessible to all commands in the series. The directory transversing commands, as described
above, are such a series. In that case,
add a field to JShellParser that will hold this date, and construct all
commands in this series with that field.
4) If you’re doing a task in your command that seems
like it might have been done before, check the classes that you inherit from to
see if that method is already implemented.
For example, if your command needs to read in a series of filenames and
run on those files, then you can use the workWithFiles method in command to
read in the files, and then put the code to deal with your file in
makeOutput(). This not only saves
redundant code, but you can also be sure that the file names are being dealt
with correctly.
The rules above hint at how
simple it is to add commands in JShell.
It takes just three easy steps.
1) Implement your command in its own *.java file,
inheriting from the lowest parent possible.
2) Add your command to the map in JShellParser
3) Compile
4) Use your new command.
This really means test it.
Two large test files are
included.
testfile.in
testfile2.in
Feel free to add input to
those files to test your commands. Also
make sure you didn’t break anything.
Notes:
It is always a good idea to
call the bool doPipedInput() that is in Command (and thus accessible to all
commands). If your command doesn’t take
piped input, this call will make sure that the StringBuffer to which you will
write your output is empty (which it might not be if the user accidentally
pipes data to a command that doesn’t take piped data).
If you use the methods
inherited from Command, then exceptions generated by those actions will be
caught. Otherwise, catch your own.
Don’t forget to append the
String variable sep for line separators instead of “\”
Problems:
No program is perfect,
JShell is no exception. Here are some of
the known issues:
printenv does not meet spec: right now printenv takes a string as an argument,
and looks up the environment variable that corresponds to that string. Spec is to print all environment variables
out. The fix would be simple…but it’s
too late now.
Directory commands not portable: through most of the code, when system dependent
items came up, the System.getProperty() values were used to achieve platform independence. However, all the directory commands rest on
the fact that “/” in Unix is the root of the file system. Drive letters, which are roots in Windows,
are not supported.
Basic file system shortcuts are not implemented: Though cd .. will succeed, it doesn’t work (the path
returned is “oldpath/..”, because .. exists as a file in Unix. None of the standard shortcuts “.”, “..”, “~”,
etc. will work.
I’m sure that’s not
all. In fact, I’m really feeling like I
forgot something. But I can’t remember.
Wanna Program:
Good places to start on
JShell would be
·
any of the
problems above
·
more commands
·
make prompt
dynamic, dependent on user and current directory
·
tab completion
·
up arrow cycle
through history
Thank you for using JShell, v1.0
Last modified