shell/src/main.cpp

144 lines
3.1 KiB
C++

#include <iostream>
#include <string>
#include <map>
#include <cstdlib>
#include <filesystem>
#include <vector>
#ifdef _WIN32
#include <process.h>
#else
#include <unistd.h>
#include <sys/wait.h>
#endif
#include "shellUtils.h"
int main()
{
std::vector<std::string> 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<std::filesystem::path> 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<char*> args;
args.push_back(const_cast<char*>(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<char*>(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;
}
}
}