/* $Id: Shell.java,v 1.11 2004/04/13 16:14:15 solomon Exp solomon $ */ import java.util.*; /** A simple command-line shell for the MiniKernel. * *

* This program displays a prompt and waits for the user to enter * command lines. * A command line consists of one or more commands, separated by * ampersands (&). * A command is the name of a Java class that implements * public static void main(String args[]), followed by * zero or more arguments to the command. * All the commands on the line are run in parallel. * The shell waits for them to finish before issuing another prompt. *

* The Shell terminates if it sees end-of-file (Control-D if input is coming * from the keyboard). *

* If this shell is invoked with any arguments, they are joined together with * spaces and run as a single command line. For example, *

 *      java Shell Test foo "& Test bar"
 * 
* is equivalent to *
 *      java Shell
 *      Shell> Test foo & Test bar
 *      Shell> exit
 * 
*

* The Shell also has the following "built-in" commands. Any arguments * are ignored. *

*
exit
The Shell terminates immediately. *
help
The Shell prints a short help message. *
?
Equivalent to help. *
* @see Kernel */ public class Shell { /** The main program. * @param args command-line arguments. If empty, prompt the user for * commands. */ public static void main(String args[]) { StringBuffer sb = new StringBuffer(); if (args.length > 0) { for (int i = 0; i < args.length; i++) { if (i > 0) { sb.append(' '); } sb.append(args[i]); } runCommandLine(sb.toString()); return; } for (;;) { Library.output("Shell> "); int rc = Library.input(sb); if (rc == Kernel.ERROR_END_OF_FILE) { return; } if (rc < 0) { Library.output("Fatal error trying to read from console\n"); System.exit(1); } if (runCommandLine(sb.toString())) { break; } } } // main(String[]) /** Help message, one line per element. */ private static String[] help = { "usage: Shell [ command [ & command] ... ]", "If no commands are specified, the Shell prompts for command lines.", "It terminates on end-of-file.", "The following commands are built in:", " exit terminate immediately", " help print this message", " ? same as help" }; /** Parses and runs one command line. * @param line the command line to run. * @return true if the command line included an exit command. */ private static boolean runCommandLine(String line) { // Split into commands separated by & StringTokenizer st = new StringTokenizer(line, "&"); int commandCount = st.countTokens(); int[] pids = new int[commandCount]; int processes = 0; boolean done = false; while (st.hasMoreTokens()) { String command = st.nextToken().trim(); // Check for special cases if (command.equals("exit")) { // Immediately exit. Don't wait for other commands if any // to complete. done = true; continue; } if (command.equals("help") || command.equals("?")) { for (int i = 0; i < help.length; i++) { Library.output(help[i] + "\n"); } continue; } // Split each command by spaces StringTokenizer cst = new StringTokenizer(command); if (!cst.hasMoreTokens()) { // empty command continue; } String program = cst.nextToken(); String[] progArgs = new String[cst.countTokens()]; for (int i = 0; cst.hasMoreTokens(); ) { progArgs[i++] = cst.nextToken(); } int pid = Library.exec(program,progArgs); if (pid < 0) { Library.output("Shell: Error executing " + program + ": " + Library.errorMessage[-pid] + "\n"); } else { pids[processes++] = pid; } } // Wait for all the processes to complete for (int i = 0; i < processes; i++) { if (Library.join(pids[i]) != 0) { Library.output("Error waiting for process " + pids[i] + " to complete\n"); } } return done; } // runCommandLine(StringBuffer) } // class Shell