sh: Add a few more shell builtins
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
16b385fc7b
commit
7a4d3ba495
@ -2,6 +2,9 @@ set(SOURCES
|
|||||||
main.cpp
|
main.cpp
|
||||||
sh.h
|
sh.h
|
||||||
builtin/cd.cpp
|
builtin/cd.cpp
|
||||||
|
builtin/exit.cpp
|
||||||
|
builtin/set.cpp
|
||||||
|
builtin/unset.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(sh ${SOURCES})
|
add_executable(sh ${SOURCES})
|
||||||
|
20
shell/builtin/exit.cpp
Normal file
20
shell/builtin/exit.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "sh.h"
|
||||||
|
#include <os/ArgumentParser.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
shell_builtin_t builtin_exit = [](int argc, char** argv) -> Result<void> {
|
||||||
|
StringView exit_status;
|
||||||
|
|
||||||
|
os::ArgumentParser parser;
|
||||||
|
parser.set_should_exit_on_bad_usage(false);
|
||||||
|
parser.add_description("Exit the shell (shell builtin)"_sv);
|
||||||
|
parser.add_system_program_info("exit"_sv);
|
||||||
|
parser.add_positional_argument(exit_status, "status"_sv, false);
|
||||||
|
if (!TRY(parser.parse(argc, argv))) return {};
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
if (!exit_status.is_empty()) { status = (int)strtoul(exit_status.chars(), nullptr, 10); }
|
||||||
|
|
||||||
|
exit(status);
|
||||||
|
};
|
24
shell/builtin/set.cpp
Normal file
24
shell/builtin/set.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include "sh.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <os/ArgumentParser.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
shell_builtin_t builtin_set = [](int argc, char** argv) -> Result<void> {
|
||||||
|
StringView name;
|
||||||
|
StringView value;
|
||||||
|
bool preserve { false };
|
||||||
|
|
||||||
|
os::ArgumentParser parser;
|
||||||
|
parser.set_should_exit_on_bad_usage(false);
|
||||||
|
parser.add_description("Set an environment variable (shell builtin)"_sv);
|
||||||
|
parser.add_system_program_info("set"_sv);
|
||||||
|
parser.add_positional_argument(name, "name"_sv, true);
|
||||||
|
parser.add_positional_argument(value, "value"_sv, true);
|
||||||
|
parser.add_switch_argument(preserve, 'p', "preserve"_sv,
|
||||||
|
"preserve the environment variable if it already exists"_sv);
|
||||||
|
if (!TRY(parser.parse(argc, argv))) return {};
|
||||||
|
|
||||||
|
if (setenv(name.chars(), value.chars(), !preserve) < 0) return err(errno);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
};
|
19
shell/builtin/unset.cpp
Normal file
19
shell/builtin/unset.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "sh.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <os/ArgumentParser.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
shell_builtin_t builtin_unset = [](int argc, char** argv) -> Result<void> {
|
||||||
|
StringView name;
|
||||||
|
|
||||||
|
os::ArgumentParser parser;
|
||||||
|
parser.set_should_exit_on_bad_usage(false);
|
||||||
|
parser.add_description("Remove an environment variable (shell builtin)"_sv);
|
||||||
|
parser.add_system_program_info("unset"_sv);
|
||||||
|
parser.add_positional_argument(name, "name"_sv, true);
|
||||||
|
if (!TRY(parser.parse(argc, argv))) return {};
|
||||||
|
|
||||||
|
if (unsetenv(name.chars()) < 0) return err(errno);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
};
|
@ -19,6 +19,9 @@
|
|||||||
#include <luna/HashMap.h>
|
#include <luna/HashMap.h>
|
||||||
|
|
||||||
extern shell_builtin_t builtin_cd;
|
extern shell_builtin_t builtin_cd;
|
||||||
|
extern shell_builtin_t builtin_exit;
|
||||||
|
extern shell_builtin_t builtin_set;
|
||||||
|
extern shell_builtin_t builtin_unset;
|
||||||
|
|
||||||
static HashMap<StringView, shell_builtin_t> s_builtins;
|
static HashMap<StringView, shell_builtin_t> s_builtins;
|
||||||
|
|
||||||
@ -44,6 +47,25 @@ static Result<void> init_builtins()
|
|||||||
s_builtins = {};
|
s_builtins = {};
|
||||||
|
|
||||||
TRY(s_builtins.try_set("cd"_sv, builtin_cd));
|
TRY(s_builtins.try_set("cd"_sv, builtin_cd));
|
||||||
|
TRY(s_builtins.try_set("exit"_sv, builtin_exit));
|
||||||
|
TRY(s_builtins.try_set("set"_sv, builtin_set));
|
||||||
|
TRY(s_builtins.try_set("unset"_sv, builtin_unset));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<void> builtin_wrapper(const Vector<String>& args, shell_builtin_t builtin)
|
||||||
|
{
|
||||||
|
Vector<const char*> argv;
|
||||||
|
for (const auto& arg : args) { TRY(argv.try_append(arg.chars())); }
|
||||||
|
TRY(argv.try_append(nullptr));
|
||||||
|
|
||||||
|
auto rc = builtin((int)args.size(), const_cast<char**>(argv.data()));
|
||||||
|
if (rc.has_error())
|
||||||
|
{
|
||||||
|
errno = rc.error();
|
||||||
|
perror(argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -73,6 +95,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
parser.add_value_argument(command, 'c', "command"_sv, "execute a single command and then exit"_sv);
|
parser.add_value_argument(command, 'c', "command"_sv, "execute a single command and then exit"_sv);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
// TODO: This does not properly handle builtins.
|
||||||
if (!command.is_empty()) TRY(execute_command(command));
|
if (!command.is_empty()) TRY(execute_command(command));
|
||||||
|
|
||||||
if (path == "-") { input_file = File::standard_input(); }
|
if (path == "-") { input_file = File::standard_input(); }
|
||||||
@ -103,7 +126,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
tcsetpgrp(STDIN_FILENO, getpgid(0));
|
tcsetpgrp(STDIN_FILENO, getpgid(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
init_builtins();
|
TRY(init_builtins());
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@ -146,16 +169,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
auto builtin = maybe_builtin.value();
|
auto builtin = maybe_builtin.value();
|
||||||
|
|
||||||
Vector<const char*> argv;
|
TRY(builtin_wrapper(args, builtin));
|
||||||
for (const auto& arg : args) { TRY(argv.try_append(arg.chars())); }
|
|
||||||
TRY(argv.try_append(nullptr));
|
|
||||||
|
|
||||||
auto rc = builtin((int)args.size(), const_cast<char**>(argv.data()));
|
|
||||||
if (rc.has_error())
|
|
||||||
{
|
|
||||||
errno = rc.error();
|
|
||||||
perror(argv[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user