#include #include #include #include #include #include #ifdef _WIN32 #include #else #include #include #endif #include "shellUtils.h" int main() { std::vector tokens; std::cout << std::unitbuf; std::cerr << std::unitbuf; bool shouldExit {false}; while (!shouldExit) { tokens.clear(); std::string input; std::string line; bool finshedInput{}; std::cout << "$ "; while (!finshedInput and std::getline(std::cin, line)) { auto end = line.size() - 1; if (line[end] == '\\') { if (end == 0) { std::cout << "> " ; } else { input += line.substr(0, line.size() - 1); std::cout << "> "; } } else { input += line; finshedInput = true; } } //trim whitespace and tabs from start and end const size_t start = input.find_first_not_of(" \t"); if (start == std::string::npos) {// the input was all whitespace and tabs input.clear(); } else { const size_t end = input.find_last_not_of(" \t"); input = input.substr(start, end - start + 1); } if (input.empty()) { continue; } //we can now assume there is actual text from the input sh::tokenize(tokens, input); std::optional result; switch (sh::Command command = sh::getCommand(tokens[0])) { case sh::Command::exit: shouldExit = true; break; case sh::Command::echo: for (int i = 1; i < tokens.size(); i++) { std::cout << tokens[i] << " "; } std::cout << "\n"; break; case sh::Command::unknown: result = sh::isExec(tokens[0]); if (result) { std::vector args; args.push_back(const_cast(result.value().filename().c_str()));// have exe path on seperate element for execv for (size_t i = 1; i < tokens.size(); i++) { args.push_back(const_cast(tokens[i].c_str())); } args.push_back(nullptr); #ifdef _WIN32 intptr_t status = _spawnv(_P_WAIT, result.value().c_str(), args.data()); if (status == -1) { perror("\n\nError executing program\n\n"); return 1; } #else pid_t pid = fork(); if (pid == 0) {// child process execv(result.value().c_str(), args.data()); perror("\n\nError executing program\n\n"); exit(1); } else { int status; waitpid(pid, &status, 0); } #endif } else { std::cout << tokens[0] << ": command not found\n"; } break; case sh::Command::type: sh::printType(tokens[1]); break; case sh::Command::pwd: std::cout << std::filesystem::current_path().string() << "\n"; break; case sh::Command::cd: sh::changeDir(tokens); break; } } }