commit 96e8d55747cc8e0e1b0082464be2ca874567976b
parent e40ef4b5852d4a92d198f57dd42f15693ee1190b
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Tue, 16 Aug 2022 23:07:18 +0100
hush: Make hush actually work as a shell
Diffstat:
M | src/hush.cpp | | | 75 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
1 file changed, 68 insertions(+), 7 deletions(-)
diff --git a/src/hush.cpp b/src/hush.cpp
@@ -2,10 +2,42 @@
#include <sstream>
#include <cstdlib>
#include <memory>
+#include <vector>
+#include <map>
#include <unistd.h>
+#include <sys/wait.h>
+#include <err.h>
using namespace std;
+void show_clear_warn(char const* msg)
+{
+ if (errno)
+ perror(msg);
+ errno = 0;
+}
+
+int cd(std::vector<char*> const& argv)
+{
+ if (argv.size() < 2)
+ {
+ cerr << "cd: not enough arguments\n";
+ return 1;
+ }
+ if (argv.size() > 2)
+ {
+ cerr << "cd: too many arguments\n";
+ return 1;
+ }
+ int res = chdir(argv[1]);
+ show_clear_warn("cd");
+ return res;
+}
+
+map<string, int(*)(std::vector<char*> const&)> intrinsics = {
+ {"cd", cd}
+};
+
auto pwd(void)
-> unique_ptr<char, void(*)(void*)>
{
@@ -16,21 +48,50 @@ int main(int, char**)
{
string buf;
- auto wd = pwd();
-
for (;;)
{
+ auto wd = pwd();
+
cout << '[' << wd.get() << "] " << flush;
if (!getline(cin, buf))
break;
- cout << buf << '\n';
-
istringstream is(buf);
- while (getline(is, buf, '\0'))
- cout << " " << buf;
+ vector<string> args;
+ while (getline(is, buf, ' '))
+ args.push_back(buf);
+
+ if (args.empty())
+ {
+ cout << '\n';
+ continue;
+ }
+ string arg0 = args.front();
+ std::vector<char*> argp;
+ for (auto& a : args)
+ {
+ a.push_back('\0');
+ argp.push_back(a.data());
+ }
+
+ if (intrinsics.contains(arg0))
+ {
+ intrinsics[arg0](argp);
+ continue;
+ }
+ argp.push_back(nullptr);
- cout << '\n';
+ if (fork())
+ {
+ int status;
+ wait(&status);
+ if (WEXITSTATUS(status))
+ std::cout << "\nResult: " << WEXITSTATUS(status) << '\n';
+ } else
+ {
+ execvp(argp[0], argp.data());
+ err(66, "execv");
+ }
}
cout << "Done!\n";