/* * hpsh: Hal Perkins' SHell * Just a simple shell. Dedicated to Hal Perkins. * Make sure to compile with C++11 support! * * Note: valgrind will complain about memory leaks. They * are all fine. Don't worry about it. */ #include #include #include #include #include #include #include #include using std::cerr; using std::cin; using std::cout; using std::endl; using std::getline; using std::string; using std::stringstream; using std::vector; static vector tokenize(const string& line); static int parse_line(const string& prompt); int main() { int ret_value; while (1) { string prompt; cout << "hpsh% "; if (!getline(cin, prompt).good()) { cout << "exit" << endl; prompt = "exit"; } ret_value = parse_line(prompt); } return ret_value; } vector tokenize(const string& line) { vector tokens; size_t cur = 0; bool curspace = true; for (size_t i = 0; i < line.size(); i++) { bool onspace = isspace(line[i]); if (onspace && !curspace) { tokens.emplace_back(line, cur, i - cur); curspace = true; } else if (!onspace && curspace) { cur = i; curspace = false; } } if (!curspace) { tokens.emplace_back(line, cur); } return tokens; } int parse_line(const string& prompt) { static int ret_value = EXIT_SUCCESS; vector tokens = tokenize(prompt); if (tokens.size() == 0) return ret_value; if (tokens[0] == "exit") { if (tokens.size() > 1) { stringstream ss (tokens[1]); ss >> ret_value; } exit(ret_value); } else if (tokens[0] == ".") { // MISSING: // open the file specified by tokens[1], // and execute each line as if the user had typed it at the prompt. // Left as an exercise to the reader :) } else if (tokens[0] == "cd") { string dir; if (tokens.size() > 1) { dir = tokens[1]; } else { dir = getenv("HOME"); } if (chdir(dir.c_str()) == -1) { cerr << "cd: " << dir << ": No such file or directory" << endl; } } else { int pid = fork(); if (pid < 0) { cerr << "Could not fork" << endl; return errno; } else if (pid == 0) { char **argv = new char*[tokens.size() + 1]; for (size_t i = 0; i < tokens.size(); i++) { argv[i] = strdup(tokens[i].c_str()); } argv[tokens.size()] = NULL; if (execvp(tokens[0].c_str(), argv) == -1) { cerr << tokens[0] << ": No such file or directory" << endl; exit(EXIT_FAILURE); } } int statloc = 0; waitpid(pid, &statloc, 0); ret_value = WEXITSTATUS(statloc); } return ret_value; }