// Shell Example Fall 2005 // #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; // Shell variables class Environment { public: string SHELL; // fully qualified shell executable string HOME; // home directory string PWD; // working directory string PATH; // shell path string Prompt() const { // construct shell for "pregnant prompt" return PWD + ">> "; } char** getENV() const { // create argv-style listing of shell variables char** envp = new char*[5]; string SH = string("SHELL=") + SHELL; envp[0] = new char[7 + SHELL.length()]; strcpy(envp[0], SH.c_str()); // ... return envp; } }; Environment Environ; // cheesy global environment... not good practice const unsigned int PATHLIMIT = 100; const unsigned int MAXARGS = 10; const char pathSeparator = '/'; void initShell(); char** getPath(unsigned int& Length); bool serviceEntry(string userEntry, char** pathList, unsigned int pathLength); bool validCommand(const string& Command, char** pathList, unsigned int pathLength, string& fullyQualifiedCommand); void cdHandler( istringstream& User ); string updatePWD(string Suffix); int main(int argc, char** argv) { initShell(); char** pathList = NULL; unsigned int pathLength = 0; pathList = getPath(pathLength); string userEntry; cout << Environ.Prompt(); getline(cin, userEntry, '\n'); while ( serviceEntry(userEntry, pathList, pathLength) ) { cout << Environ.Prompt(); getline(cin, userEntry, '\n'); } return 0; } void initShell() { char* value = getenv("HOME"); Environ.HOME = string(value); // ... } bool serviceEntry(string userEntry, char** pathList, unsigned int pathLength) { string Command; istringstream User(userEntry); User >> Command; if ( Command == "quit" ) { // internal command "quit" return false; } else if ( Command == "cd" ) { // internal command "cd" cdHandler( User ); } // ... else { // external program invocation string fullyQualified; // check for existence/executability of specified program (and get its fully-qualified name) if ( !validCommand(Command, pathList, pathLength, fullyQualified) ) { cout << "McShell could not find the command: " << fullyQualified << endl; return true; } char* argv[MAXARGS]; unsigned int argc = 0; argv[argc] = new char[Command.length() + 1]; strcpy(argv[argc], Command.c_str()); argc++; // Grab command-line parameters here string Arg; User >> Arg; while ( User ) { // ... User >> Arg; } argv[argc] = NULL; // ... int childPID = -1; if ( (childPID = fork()) == 0 ) { char** envp = Environ.getENV(); execve(fullyQualified.c_str(), argv, envp); exit(0); } // ... } return true; } char** getPath(unsigned int& Length) { char** pathList = NULL; Length = 0; //parse out path components into argc-like structure return pathList; } void cdHandler( istringstream& User ) { string newDirectory; User >> newDirectory; if ( newDirectory.length() == 0 ) { cout << Environ.PWD << endl; } else if ( newDirectory == "./" || newDirectory == "." ) { // no change return; } else { string newPWD = updatePWD( newDirectory ); Environ.PWD = newPWD; setenv("PWD", newPWD.c_str(), true); } } string updatePWD(string Suffix) { // reset PWD, compressing if needed (e.g., for "cd ..") }