//File: shell.java //CS 471 - Operating Systems Project //Dennis Pereira, Ely Soto, John Cavalieri //This file contains the shell of the operating system //as opposed to the GUI, the shell is the code that prompts //the user for commands. //Within the shell, and contained in this file, is the parser. //The parser disects a user input line and recognizes commands, //as opposed to arguments, as opposed to pipes, and input and output //redirection. import java.io.*; import java.util.*; public class shell extends VMachine { //shell handle name String shhname; boolean initialrun; String initialworker; public shell () { // Used when new instance created } public shell (String name) { // Used when creating new shell //create a new console window //this is the GUI used with our simulator ConsoleWindow console = new ConsoleWindow(name); } public void run () { //begin running the shell try { //prompt the user sysapi.Write(OUT,"% "); //read in the user input String str = sysapi.Read(IN); //convert user input to all lower case String exitstr = str.toLowerCase(); String path = ""; //create a new instance of a parser //a new instance of the parser is created for each command line Parser line = new Parser(); //create a new command Command cmd = new Command(); //keep the console window open until the logout command is given //or until the "force_exit" command is given //this is a hidden pattern used only by the creators to kill the active console window while(exitstr.compareTo("force_exit") != 0)//console.Active()) { //test to see if the user typed anything if(str.compareTo("") != 0) { //if the user type anything then create a new command array //this is an array the holds the commands given by the user CommandArray inputLine = new CommandArray(); try { //attempt to parse the user input inputLine = line.Parse(str); } catch (Exception e) { //if the attempt to parse the user input fails //then display and error with the reason //why the attempt failed String temp_error = e.toString(); String sub_temp_error = temp_error.substring(21); try { sysapi.Write(OUT, sub_temp_error +"\n"); } catch (Exception ef) { } } //after reading the entire command line //execute the commands execute(inputLine); if(sysapi.findUser(owner).isClosing) { break; } } try { //determine the path of the current logged in user path = sysapi.findUser(owner).getcurrentPath().substring(22,sysapi.findUser(owner).getcurrentPath().length() - 1) + " "; if(path.compareTo(" ")==0) { path = ""; } } catch(IndexOutOfBoundsException iobe) { path = ""; } //display the next prompt, read the user input, and proceed into the next iteration of the loop sysapi.Write(OUT,path + "% "); str = sysapi.Read(IN); exitstr = str.toLowerCase(); }//while not "force_exit" }//try catch (Exception e) {} sysapi.Exit(vmh,owner); }//run //this is where the user commands are executed //after a command line has been parsed this procedure is called //to execute all of the commands on the command line public void execute(CommandArray inputLine) { //create a new instance of the command loader FileClassLoader fileclass = null; fileclass = new FileClassLoader(); fileclass.bindir = sysapi.findUser(owner).getcurrentPath(); Class newclass = null; int argstart; int i=0; //create a new command Command cmd = new Command(); cmd = inputLine.Commands[0]; Handle pipehandle = null; //inputLine.count contains the number of commands that are on a command line //loop once for each command while (i < inputLine.count) { //create a virtual machine for each command on the command line VMachine vm1 = null; //create a handle for the input Handle current_in; //create a handle for the output Handle current_out; //if there is no input redirection if (cmd.in_flag != 0) { //use the STDIN current_in = sysapi.OpenFile(sysapi.findUser(owner).getcurrentPath() + cmd.input); } else if (i-1 >= 0 ) { //there is input redirection //if it is the first command on the line, then use the input assigned //System.out.println("Setting InPipe"); current_in = pipehandle; } else { //there is a piping condition //so the input is the output of the previous command current_in = IN; } //if there is no output redirection if (cmd.out_flag != 0) { //set the output to the STDOUT current_out = sysapi.OpenFile(sysapi.findUser(owner).getcurrentPath() + cmd.output); } else if (i+1 < inputLine.count) { //there is output redirection //if it is the last command on the line, then used the assigned output //System.out.println("Setting OutPipe"); pipehandle = sysapi.CreatePipe(); current_out = pipehandle; } else { //otherwise there is a piping condition //so set the output to the pipe, which will be used as the input to the next command current_out = OUT; } String[] cmdargs = new String[cmd.argcount]; // Arguments Passed to Workers int tempargcount = 0; //for each argument, remove whitespace for (tempargcount = 0; tempargcount < cmd.argcount; tempargcount++) { cmdargs[tempargcount] = cmd.args[tempargcount].trim(); } try { //try to load the command from the user directory try { fileclass.bindir = sysapi.findUser(owner).getcurrentPath(); newclass = fileclass.loadCmd(cmd.command); try { //set the handle of the VM Handle vmh1 = sysapi.CreateVM(current_in,current_out,newclass,owner,cmdargs,this,null,0); sysapi.findUser(owner).addHandle(vmh1); } catch(Exception e) { try { //the command could not be loaded, so display error sysapi.Write(OUT,"Program could not execute.\n"); } catch (Exception ex) {} } } catch(Exception ncex) { //the command was not found in the user directory //try to load the command from the default \bin directory try { fileclass.bindir = "C:\\java\\OSVM\\bin\\"; newclass = fileclass.loadCmd(cmd.command); try { Handle vmh1 = sysapi.CreateVM(current_in,current_out,newclass,owner,cmdargs,this,null,0); sysapi.findUser(owner).addHandle(vmh1); } catch(Exception e) { try { sysapi.Write(OUT,"Program could not execute.\n"); } catch (Exception ex) {} } } catch(Exception ncoex) { try { sysapi.Write(OUT,"Command not recognized or not found.\n"); if (current_out.getID().startsWith("pipe")) {// Handles cases where cmd with an out pipe never executes ((Pipe)current_out.getType()).close(); //sysapi.Write(current_out,""); } } catch (Exception e) { System.out.println(e); } } } } catch(Exception ex) { System.out.println(ex); } //one command was executed, now proceed to the next command i++; cmd = inputLine.Commands[i]; }//end while sysapi.Compute(vmh); }//end execute //class to store the elements of a command line class Command { public String command = ""; public String[] args = new String[1000]; public int in_flag = 0; public int out_flag = 0; public String input = ""; public String output = ""; public int argcount = 0; public void ArgAppend(String nArg){ args[argcount] = nArg; argcount++; } } //array of commands to hold in case of piping class CommandArray { public Command[] Commands = new Command[20]; public int count = 0; //adds a new command to the list public void Append(Command nCommand){ Commands[count] = (nCommand); count++; } } //the guts of the parser class Parser { //------------------------------- //checker functions - look for identifiers, input, output, and pipes //check to see if p is a command public boolean isIdentifier(String p) { int len = p.length(); for (int i=0; i') {//( ! Character.isLetterOrDigit( c ) && c != '.' && c!='/') return false; } } return true; } //check to see if p is input redirection public boolean isInputRedirect(String p) { if (p.charAt(0)=='<') { return true; } return false; } //check to see if p is output redirection public boolean isOutputRedirect(String p) { if(p.charAt(0)=='>') { return true; } return false; } //check to see if p is a pipe public boolean isPipe(String p){ if(p.charAt(0)=='|') { return true; } return false; } //------------------------------------------------- //below is the parse function public CommandArray Parse( String lineToParse ) throws Exception { //declarations int state = 0; //current state int xstate = 0; //previous state int vmcount = 0; //number of commands int pipecount = 0; //number of pipes boolean gotToken = false; //available token String t =""; boolean expecting = true; //expecting more tokens on a line boolean done = false; //the command line has reached the end Command currentCommand = new Command(); CommandArray cmd_list = new CommandArray(); StringTokenizer tokens = new StringTokenizer(lineToParse); //check the line and continue while there is text on the line NEXT:while (gotToken || tokens.hasMoreTokens()) { if (!gotToken){ t = tokens.nextToken(); } gotToken = false; if (done){ throw(new Exception("Unexpected Continuation of Line")); } //switch on states switch (state){ case 0: //state for command //this must be an identifier to a command if (isIdentifier(t)) { //we have a command currentCommand.command=t; vmcount ++; state = 1; } else { //if not an Identifier (a letter followed by letters or digits) //error throw(new Exception("Command Expected. Found: \"" + t + "\"")); } expecting = false; continue NEXT; case 1: //could be: inputredir, outputredir, pipe, arguement, or nothing //check for input redirect if (isInputRedirect(t)){ xstate = state; state=2; expecting = true; if (t.length()>1) { t = t.substring(1); gotToken = true; continue NEXT; } else { gotToken = false; continue NEXT; } //check for output redirect } else if(isOutputRedirect(t)) { xstate = state; state=4; expecting = true; if (t.length()>1){ t = t.substring(1); gotToken = true; continue NEXT; } else { gotToken = false; continue NEXT; } //check for a pipe } else if(isPipe(t)){ pipecount++; xstate = state; state=5; expecting = true; cmd_list.Append(currentCommand); currentCommand = new Command(); if (t.length()>1){ t = t.substring(1); gotToken = true; continue NEXT; } else { gotToken = false; continue NEXT; } } //if not a pipe, not input, not output, must be an argument if (!isPipe(t) && !isOutputRedirect(t) && !isInputRedirect(t)) { //return an argument in command.args expecting = false; currentCommand.ArgAppend(t); } continue NEXT; case 2: //state for input redirect state = 3; //check to make sure you only accept one input redirect if (isIdentifier(t)) { currentCommand.input = t; currentCommand.in_flag = 1; expecting = false; } else { //error throw(new Exception("ERROR: Expecting Input File Name. Found: " + t)); } continue NEXT; case 3: //state for after input redirect - can be either pipe or output redirect xstate = state; //if its output redirection if(isOutputRedirect(t)) { state=4; expecting = true; if (t.length()>1){ t = t.substring(1); gotToken = true; continue NEXT; } else { gotToken = false; continue NEXT; } } //otherwise its a pipe else if(isPipe(t)) { pipecount++; state=5; expecting = true; cmd_list.Append(currentCommand); currentCommand = new Command(); if (t.length()>1){ t = t.substring(1); gotToken = true; continue NEXT; } else { gotToken = false; continue NEXT; } } //if it is not output redirection or a pipe, it must be a pipe else if (isIdentifier(t)) { //return an argument in command.args expecting = false; currentCommand.ArgAppend(t); } //if it is none of the above, then generate an error if (!isPipe(t) && !isOutputRedirect(t) && !isIdentifier(t)) { //error throw (new Exception( "ERROR: Expecting Argument, Pipe, or Output Redirection. Found: \"" + t + "\"")); } continue NEXT; case 4: //state for output redirection state = xstate; if (isIdentifier(t)){ currentCommand.output = t; currentCommand.out_flag = 1; expecting = false; done = true; } else { //error throw(new Exception("File Name Expected. Found:"+t)); } continue NEXT; case 5: if (isIdentifier(t)){ //a command has been recognized currentCommand.command=t; state = 3; expecting = false; vmcount++; } else { //error throw(new Exception("Command Expected. Found:"+t)); } continue NEXT; default: // out.println("In State x:" + t); break; } if ( expecting ){ throw(new Exception("Unexpected end of line")); } } //end NEXTswitch cmd_list.Append(currentCommand); return cmd_list; } //end parse } //end class }