mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
Shell: Convert builtins to use the modern main() style
That is, return ErrorOr<int>, handle fallible ops with TRY() and accept a Main::Arguments. Note that we do not populate the argc/argv members of Main::Arguments, so all accesses have to go through .strings.
This commit is contained in:
parent
6e5ba82929
commit
007767fc14
Notes:
sideshowbarker
2024-07-16 23:38:27 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/007767fc14 Pull-request: https://github.com/SerenityOS/serenity/pull/17538 Reviewed-by: https://github.com/ADKaster
3 changed files with 175 additions and 148 deletions
|
@ -26,12 +26,12 @@ extern char** environ;
|
|||
|
||||
namespace Shell {
|
||||
|
||||
int Shell::builtin_noop(int, char const**)
|
||||
ErrorOr<int> Shell::builtin_noop(Main::Arguments)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_dump(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_dump(Main::Arguments arguments)
|
||||
{
|
||||
bool posix = false;
|
||||
StringView source;
|
||||
|
@ -40,10 +40,10 @@ int Shell::builtin_dump(int argc, char const** argv)
|
|||
parser.add_positional_argument(source, "Shell code to parse and dump", "source");
|
||||
parser.add_option(posix, "Use the POSIX parser", "posix", 'p');
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
(void)(posix ? Posix::Parser { source }.parse() : Parser { source }.parse())->dump(0);
|
||||
TRY((posix ? Posix::Parser { source }.parse() : Parser { source }.parse())->dump(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -80,20 +80,20 @@ static Vector<DeprecatedString> find_matching_executables_in_path(StringView fil
|
|||
return executables;
|
||||
}
|
||||
|
||||
int Shell::builtin_where(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_where(Main::Arguments arguments)
|
||||
{
|
||||
Vector<StringView> arguments;
|
||||
Vector<StringView> values_to_lookup;
|
||||
bool do_only_path_search { false };
|
||||
bool do_follow_symlinks { false };
|
||||
bool do_print_only_type { false };
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(arguments, "List of shell builtins, aliases or executables", "arguments");
|
||||
parser.add_positional_argument(values_to_lookup, "List of shell builtins, aliases or executables", "arguments");
|
||||
parser.add_option(do_only_path_search, "Search only for executables in the PATH environment variable", "path-only", 'p');
|
||||
parser.add_option(do_follow_symlinks, "Follow symlinks and print the symlink free path", "follow-symlink", 's');
|
||||
parser.add_option(do_print_only_type, "Print the argument type instead of a human readable description", "type", 'w');
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
auto const lookup_alias = [do_only_path_search, &m_aliases = this->m_aliases](StringView alias) -> Optional<DeprecatedString> {
|
||||
|
@ -114,7 +114,7 @@ int Shell::builtin_where(int argc, char const** argv)
|
|||
};
|
||||
|
||||
bool at_least_one_succeded { false };
|
||||
for (auto const& argument : arguments) {
|
||||
for (auto const& argument : values_to_lookup) {
|
||||
auto const alias = lookup_alias(argument);
|
||||
if (alias.has_value()) {
|
||||
if (do_print_only_type)
|
||||
|
@ -147,24 +147,24 @@ int Shell::builtin_where(int argc, char const** argv)
|
|||
return at_least_one_succeded ? 0 : 1;
|
||||
}
|
||||
|
||||
int Shell::builtin_alias(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_alias(Main::Arguments arguments)
|
||||
{
|
||||
Vector<DeprecatedString> arguments;
|
||||
Vector<DeprecatedString> aliases;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(arguments, "List of name[=values]'s", "name[=value]", Core::ArgsParser::Required::No);
|
||||
parser.add_positional_argument(aliases, "List of name[=values]'s", "name[=value]", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (arguments.is_empty()) {
|
||||
if (aliases.is_empty()) {
|
||||
for (auto& alias : m_aliases)
|
||||
printf("%s=%s\n", escape_token(alias.key).characters(), escape_token(alias.value).characters());
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
for (auto& argument : arguments) {
|
||||
for (auto& argument : aliases) {
|
||||
auto parts = argument.split_limit('=', 2, SplitBehavior::KeepEmpty);
|
||||
if (parts.size() == 1) {
|
||||
auto alias = m_aliases.get(parts[0]);
|
||||
|
@ -182,17 +182,17 @@ int Shell::builtin_alias(int argc, char const** argv)
|
|||
return fail ? 1 : 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_unalias(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_unalias(Main::Arguments arguments)
|
||||
{
|
||||
bool remove_all { false };
|
||||
Vector<DeprecatedString> arguments;
|
||||
Vector<DeprecatedString> aliases;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.set_general_help("Remove alias from the list of aliases");
|
||||
parser.add_option(remove_all, "Remove all aliases", nullptr, 'a');
|
||||
parser.add_positional_argument(arguments, "List of aliases to remove", "alias", Core::ArgsParser::Required::No);
|
||||
parser.add_positional_argument(aliases, "List of aliases to remove", "alias", Core::ArgsParser::Required::Yes);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (remove_all) {
|
||||
|
@ -201,14 +201,8 @@ int Shell::builtin_unalias(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (arguments.is_empty()) {
|
||||
warnln("unalias: not enough arguments");
|
||||
parser.print_usage(stderr, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool failed { false };
|
||||
for (auto& argument : arguments) {
|
||||
for (auto& argument : aliases) {
|
||||
if (!m_aliases.contains(argument)) {
|
||||
warnln("unalias: {}: alias not found", argument);
|
||||
failed = true;
|
||||
|
@ -221,7 +215,7 @@ int Shell::builtin_unalias(int argc, char const** argv)
|
|||
return failed ? 1 : 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_bg(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_bg(Main::Arguments arguments)
|
||||
{
|
||||
int job_id = -1;
|
||||
bool is_pid = false;
|
||||
|
@ -251,7 +245,7 @@ int Shell::builtin_bg(int argc, char const** argv)
|
|||
return false;
|
||||
} });
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (job_id == -1 && !jobs.is_empty())
|
||||
|
@ -286,7 +280,7 @@ int Shell::builtin_bg(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_type(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_type(Main::Arguments arguments)
|
||||
{
|
||||
Vector<DeprecatedString> commands;
|
||||
bool dont_show_function_source = false;
|
||||
|
@ -296,7 +290,7 @@ int Shell::builtin_type(int argc, char const** argv)
|
|||
parser.add_positional_argument(commands, "Command(s) to list info about", "command");
|
||||
parser.add_option(dont_show_function_source, "Do not show functions source.", "no-fn-source", 'f');
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
bool something_not_found = false;
|
||||
|
@ -355,14 +349,14 @@ int Shell::builtin_type(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_cd(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_cd(Main::Arguments arguments)
|
||||
{
|
||||
char const* arg_path = nullptr;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(arg_path, "Path to change to", "path", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
DeprecatedString new_path;
|
||||
|
@ -409,14 +403,14 @@ int Shell::builtin_cd(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_cdh(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_cdh(Main::Arguments arguments)
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(index, "Index of the cd history entry (leave out for a list)", "index", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (index == -1) {
|
||||
|
@ -435,12 +429,12 @@ int Shell::builtin_cdh(int argc, char const** argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
char const* path = cd_history.at(cd_history.size() - index).characters();
|
||||
char const* cd_args[] = { "cd", path, nullptr };
|
||||
return Shell::builtin_cd(2, cd_args);
|
||||
StringView path = cd_history.at(cd_history.size() - index);
|
||||
StringView cd_args[] = { "cd"sv, path };
|
||||
return Shell::builtin_cd({ .argc = 0, .argv = 0, .strings = cd_args });
|
||||
}
|
||||
|
||||
int Shell::builtin_dirs(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_dirs(Main::Arguments arguments)
|
||||
{
|
||||
// The first directory in the stack is ALWAYS the current directory
|
||||
directory_stack.at(0) = cwd.characters();
|
||||
|
@ -458,7 +452,7 @@ int Shell::builtin_dirs(int argc, char const** argv)
|
|||
parser.add_option(number_when_printing, "Number the directories in the stack when printing", "number", 'v');
|
||||
parser.add_positional_argument(paths, "Extra paths to put on the stack", "path", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
// -v implies -p
|
||||
|
@ -493,26 +487,24 @@ int Shell::builtin_dirs(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_exec(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_exec(Main::Arguments arguments)
|
||||
{
|
||||
if (argc < 2) {
|
||||
if (arguments.strings.size() < 2) {
|
||||
warnln("Shell: No command given to exec");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Vector<char const*> argv_vector;
|
||||
argv_vector.append(argv + 1, argc - 1);
|
||||
argv_vector.append(nullptr);
|
||||
|
||||
execute_process(move(argv_vector));
|
||||
TRY(execute_process(arguments.strings.slice(1)));
|
||||
// NOTE: Won't get here.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_exit(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_exit(Main::Arguments arguments)
|
||||
{
|
||||
int exit_code = 0;
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(exit_code, "Exit code", "code", Core::ArgsParser::Required::No);
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (m_is_interactive) {
|
||||
|
@ -532,14 +524,14 @@ int Shell::builtin_exit(int argc, char const** argv)
|
|||
exit(exit_code);
|
||||
}
|
||||
|
||||
int Shell::builtin_export(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_export(Main::Arguments arguments)
|
||||
{
|
||||
Vector<DeprecatedString> vars;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(vars, "List of variable[=value]'s", "values", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (vars.is_empty()) {
|
||||
|
@ -554,7 +546,7 @@ int Shell::builtin_export(int argc, char const** argv)
|
|||
if (parts.size() == 1) {
|
||||
auto value = lookup_local_variable(parts[0]);
|
||||
if (value) {
|
||||
auto values = const_cast<AST::Value&>(*value).resolve_as_list(*this).release_value_but_fixme_should_propagate_errors();
|
||||
auto values = TRY(const_cast<AST::Value&>(*value).resolve_as_list(*this));
|
||||
StringBuilder builder;
|
||||
builder.join(' ', values);
|
||||
parts.append(builder.to_deprecated_string());
|
||||
|
@ -578,13 +570,13 @@ int Shell::builtin_export(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_glob(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_glob(Main::Arguments arguments)
|
||||
{
|
||||
Vector<DeprecatedString> globs;
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(globs, "Globs to resolve", "glob");
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
for (auto& glob : globs) {
|
||||
|
@ -595,7 +587,7 @@ int Shell::builtin_glob(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_fg(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_fg(Main::Arguments arguments)
|
||||
{
|
||||
int job_id = -1;
|
||||
bool is_pid = false;
|
||||
|
@ -625,7 +617,7 @@ int Shell::builtin_fg(int argc, char const** argv)
|
|||
return false;
|
||||
} });
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (job_id == -1 && !jobs.is_empty())
|
||||
|
@ -667,7 +659,7 @@ int Shell::builtin_fg(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_disown(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_disown(Main::Arguments arguments)
|
||||
{
|
||||
Vector<int> job_ids;
|
||||
Vector<bool> id_is_pid;
|
||||
|
@ -697,7 +689,7 @@ int Shell::builtin_disown(int argc, char const** argv)
|
|||
return false;
|
||||
} });
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (job_ids.is_empty()) {
|
||||
|
@ -736,7 +728,7 @@ int Shell::builtin_disown(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_history(int, char const**)
|
||||
ErrorOr<int> Shell::builtin_history(Main::Arguments)
|
||||
{
|
||||
for (size_t i = 0; i < m_editor->history().size(); ++i) {
|
||||
printf("%6zu %s\n", i + 1, m_editor->history()[i].entry.characters());
|
||||
|
@ -744,7 +736,7 @@ int Shell::builtin_history(int, char const**)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_jobs(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_jobs(Main::Arguments arguments)
|
||||
{
|
||||
bool list = false, show_pid = false;
|
||||
|
||||
|
@ -752,7 +744,7 @@ int Shell::builtin_jobs(int argc, char const** argv)
|
|||
parser.add_option(list, "List all information about jobs", "list", 'l');
|
||||
parser.add_option(show_pid, "Display the PID of the jobs", "pid", 'p');
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
Job::PrintStatusMode mode = Job::PrintStatusMode::Basic;
|
||||
|
@ -771,7 +763,7 @@ int Shell::builtin_jobs(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_popd(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_popd(Main::Arguments arguments)
|
||||
{
|
||||
if (directory_stack.size() <= 1) {
|
||||
warnln("Shell: popd: directory stack empty");
|
||||
|
@ -782,7 +774,7 @@ int Shell::builtin_popd(int argc, char const** argv)
|
|||
Core::ArgsParser parser;
|
||||
parser.add_option(should_not_switch, "Do not switch dirs", "no-switch", 'n');
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
auto popped_path = directory_stack.take_last();
|
||||
|
@ -799,14 +791,14 @@ int Shell::builtin_popd(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_pushd(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_pushd(Main::Arguments arguments)
|
||||
{
|
||||
StringBuilder path_builder;
|
||||
bool should_switch = true;
|
||||
|
||||
// From the BASH reference manual: https://www.gnu.org/software/bash/manual/html_node/Directory-Stack-Builtins.html
|
||||
// With no arguments, pushd exchanges the top two directories and makes the new top the current directory.
|
||||
if (argc == 1) {
|
||||
if (arguments.strings.size() == 1) {
|
||||
if (directory_stack.size() < 2) {
|
||||
warnln("pushd: no other directory");
|
||||
return 1;
|
||||
|
@ -829,26 +821,27 @@ int Shell::builtin_pushd(int argc, char const** argv)
|
|||
}
|
||||
|
||||
// Let's assume the user's typed in 'pushd <dir>'
|
||||
if (argc == 2) {
|
||||
if (arguments.strings.size() == 2) {
|
||||
directory_stack.append(cwd.characters());
|
||||
if (argv[1][0] == '/') {
|
||||
path_builder.append({ argv[1], strlen(argv[1]) });
|
||||
if (arguments.strings[1].starts_with('/')) {
|
||||
path_builder.append(arguments.strings[1]);
|
||||
} else {
|
||||
path_builder.appendff("{}/{}", cwd, argv[1]);
|
||||
path_builder.appendff("{}/{}", cwd, arguments.strings[1]);
|
||||
}
|
||||
} else if (argc == 3) {
|
||||
} else if (arguments.strings.size() == 3) {
|
||||
directory_stack.append(cwd.characters());
|
||||
for (int i = 1; i < argc; i++) {
|
||||
char const* arg = argv[i];
|
||||
for (size_t i = 1; i < arguments.strings.size(); i++) {
|
||||
auto arg = arguments.strings[i];
|
||||
|
||||
if (arg[0] != '-') {
|
||||
if (arg[0] == '/') {
|
||||
path_builder.append({ arg, strlen(arg) });
|
||||
} else
|
||||
if (arg.starts_with('-')) {
|
||||
if (arg.starts_with('/')) {
|
||||
path_builder.append(arg);
|
||||
} else {
|
||||
path_builder.appendff("{}/{}", cwd, arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "-n"))
|
||||
if (arg == "-n"sv)
|
||||
should_switch = false;
|
||||
}
|
||||
}
|
||||
|
@ -880,16 +873,16 @@ int Shell::builtin_pushd(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_pwd(int, char const**)
|
||||
ErrorOr<int> Shell::builtin_pwd(Main::Arguments)
|
||||
{
|
||||
print_path(cwd);
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_setopt(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_setopt(Main::Arguments arguments)
|
||||
{
|
||||
if (argc == 1) {
|
||||
if (arguments.strings.size() == 1) {
|
||||
#define __ENUMERATE_SHELL_OPTION(name, default_, description) \
|
||||
if (options.name) \
|
||||
warnln("{}", #name);
|
||||
|
@ -910,7 +903,7 @@ int Shell::builtin_setopt(int argc, char const** argv)
|
|||
|
||||
#undef __ENUMERATE_SHELL_OPTION
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
#define __ENUMERATE_SHELL_OPTION(name, default_, description) \
|
||||
|
@ -926,14 +919,14 @@ int Shell::builtin_setopt(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_shift(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_shift(Main::Arguments arguments)
|
||||
{
|
||||
int count = 1;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(count, "Shift count", "count", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (count < 1)
|
||||
|
@ -960,7 +953,7 @@ int Shell::builtin_shift(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_source(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_source(Main::Arguments arguments)
|
||||
{
|
||||
char const* file_to_source = nullptr;
|
||||
Vector<StringView> args;
|
||||
|
@ -969,7 +962,7 @@ int Shell::builtin_source(int argc, char const** argv)
|
|||
parser.add_positional_argument(file_to_source, "File to read commands from", "path");
|
||||
parser.add_positional_argument(args, "ARGV for the sourced file", "args", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv)))
|
||||
if (!parser.parse(arguments))
|
||||
return 1;
|
||||
|
||||
auto previous_argv = lookup_local_variable("ARGV"sv);
|
||||
|
@ -982,7 +975,7 @@ int Shell::builtin_source(int argc, char const** argv)
|
|||
Vector<String> arguments;
|
||||
arguments.ensure_capacity(args.size());
|
||||
for (auto& arg : args)
|
||||
arguments.append(String::from_utf8(arg).release_value_but_fixme_should_propagate_errors());
|
||||
arguments.append(TRY(String::from_utf8(arg)));
|
||||
|
||||
set_local_variable("ARGV", AST::make_ref_counted<AST::ListValue>(move(arguments)));
|
||||
}
|
||||
|
@ -993,7 +986,7 @@ int Shell::builtin_source(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_time(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_time(Main::Arguments arguments)
|
||||
{
|
||||
Vector<StringView> args;
|
||||
|
||||
|
@ -1004,16 +997,16 @@ int Shell::builtin_time(int argc, char const** argv)
|
|||
parser.set_stop_on_first_non_option(true);
|
||||
parser.add_positional_argument(args, "Command to execute with arguments", "command", Core::ArgsParser::Required::Yes);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (number_of_iterations < 1)
|
||||
return 1;
|
||||
|
||||
AST::Command command;
|
||||
command.argv.ensure_capacity(args.size());
|
||||
TRY(command.argv.try_ensure_capacity(args.size()));
|
||||
for (auto& arg : args)
|
||||
command.argv.append(String::from_utf8(arg).release_value_but_fixme_should_propagate_errors());
|
||||
command.argv.append(TRY(String::from_utf8(arg)));
|
||||
|
||||
auto commands = expand_aliases({ move(command) });
|
||||
|
||||
|
@ -1038,7 +1031,7 @@ int Shell::builtin_time(int argc, char const** argv)
|
|||
|
||||
warnln("Timing report: {} ms", iteration_times.sum());
|
||||
warnln("==============");
|
||||
warnln("Command: {}", DeprecatedString::join(' ', Span<char const*>(argv, argc)));
|
||||
warnln("Command: {}", DeprecatedString::join(' ', arguments.strings));
|
||||
warnln("Average time: {:.2} ms (median: {}, stddev: {:.2}, min: {}, max:{})",
|
||||
iteration_times.average(), iteration_times.median(),
|
||||
iteration_times.standard_deviation(),
|
||||
|
@ -1052,14 +1045,14 @@ int Shell::builtin_time(int argc, char const** argv)
|
|||
return exit_code;
|
||||
}
|
||||
|
||||
int Shell::builtin_umask(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_umask(Main::Arguments arguments)
|
||||
{
|
||||
char const* mask_text = nullptr;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(mask_text, "New mask (omit to get current mask)", "octal-mask", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
if (!mask_text) {
|
||||
|
@ -1080,7 +1073,7 @@ int Shell::builtin_umask(int argc, char const** argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int Shell::builtin_wait(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_wait(Main::Arguments arguments)
|
||||
{
|
||||
Vector<int> job_ids;
|
||||
Vector<bool> id_is_pid;
|
||||
|
@ -1110,7 +1103,7 @@ int Shell::builtin_wait(int argc, char const** argv)
|
|||
return false;
|
||||
} });
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
Vector<NonnullRefPtr<Job>> jobs_to_wait_for;
|
||||
|
@ -1138,14 +1131,14 @@ int Shell::builtin_wait(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_unset(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_unset(Main::Arguments arguments)
|
||||
{
|
||||
Vector<DeprecatedString> vars;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_positional_argument(vars, "List of variables", "variables", Core::ArgsParser::Required::Yes);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage))
|
||||
return 1;
|
||||
|
||||
bool did_touch_path = false;
|
||||
|
@ -1166,15 +1159,21 @@ int Shell::builtin_unset(int argc, char const** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_not(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_not(Main::Arguments arguments)
|
||||
{
|
||||
// FIXME: Use ArgsParser when it can collect unrelated -arguments too.
|
||||
if (argc == 1)
|
||||
Vector<StringView> args;
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.set_stop_on_first_non_option(true);
|
||||
parser.add_positional_argument(args, "Command to run followed by its arguments", "string");
|
||||
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::Ignore))
|
||||
return 1;
|
||||
|
||||
AST::Command command;
|
||||
for (size_t i = 1; i < (size_t)argc; ++i)
|
||||
command.argv.append(String::from_utf8(StringView { argv[i], strlen(argv[i]) }).release_value_but_fixme_should_propagate_errors());
|
||||
TRY(command.argv.try_ensure_capacity(args.size()));
|
||||
for (auto& arg : args)
|
||||
command.argv.unchecked_append(TRY(String::from_utf8(arg)));
|
||||
|
||||
auto commands = expand_aliases({ move(command) });
|
||||
int exit_code = 1;
|
||||
|
@ -1190,7 +1189,7 @@ int Shell::builtin_not(int argc, char const** argv)
|
|||
return exit_code == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
int Shell::builtin_kill(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_kill(Main::Arguments arguments)
|
||||
{
|
||||
// Simply translate the arguments and pass them to `kill'
|
||||
Vector<String> replaced_values;
|
||||
|
@ -1199,18 +1198,19 @@ int Shell::builtin_kill(int argc, char const** argv)
|
|||
warnln("kill: `kill' not found in PATH");
|
||||
return 126;
|
||||
}
|
||||
replaced_values.append(String::from_deprecated_string(kill_path.release_value()).release_value_but_fixme_should_propagate_errors());
|
||||
for (auto i = 1; i < argc; ++i) {
|
||||
if (auto job_id = resolve_job_spec({ argv[i], strlen(argv[1]) }); job_id.has_value()) {
|
||||
|
||||
replaced_values.append(TRY(String::from_deprecated_string(kill_path.release_value())));
|
||||
for (size_t i = 1; i < arguments.strings.size(); ++i) {
|
||||
if (auto job_id = resolve_job_spec(arguments.strings[i]); job_id.has_value()) {
|
||||
auto job = find_job(job_id.value());
|
||||
if (job) {
|
||||
replaced_values.append(String::number(job->pid()).release_value_but_fixme_should_propagate_errors());
|
||||
replaced_values.append(TRY(String::number(job->pid())));
|
||||
} else {
|
||||
warnln("kill: Job with pid {} not found", job_id.value());
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
replaced_values.append(String::from_deprecated_string(argv[i]).release_value_but_fixme_should_propagate_errors());
|
||||
replaced_values.append(TRY(String::from_utf8(arguments.strings[i])));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1233,7 +1233,7 @@ int Shell::builtin_kill(int argc, char const** argv)
|
|||
return exit_code;
|
||||
}
|
||||
|
||||
bool Shell::run_builtin(const AST::Command& command, NonnullRefPtrVector<AST::Rewiring> const& rewirings, int& retval)
|
||||
ErrorOr<bool> Shell::run_builtin(const AST::Command& command, NonnullRefPtrVector<AST::Rewiring> const& rewirings, int& retval)
|
||||
{
|
||||
if (command.argv.is_empty())
|
||||
return false;
|
||||
|
@ -1241,15 +1241,16 @@ bool Shell::run_builtin(const AST::Command& command, NonnullRefPtrVector<AST::Re
|
|||
if (!has_builtin(command.argv.first()))
|
||||
return false;
|
||||
|
||||
// FIXME: Make all the functions above take the more idiomatic (Main::Arguments) parameters, and remove this gross conversion.
|
||||
Vector<char const*> argv;
|
||||
Vector<DeprecatedString> args;
|
||||
for (auto& arg : command.argv) {
|
||||
args.append(arg.to_deprecated_string());
|
||||
argv.append(args.last().characters());
|
||||
}
|
||||
Vector<StringView> arguments;
|
||||
TRY(arguments.try_ensure_capacity(command.argv.size()));
|
||||
for (auto& arg : command.argv)
|
||||
arguments.unchecked_append(arg);
|
||||
|
||||
argv.append(nullptr);
|
||||
Main::Arguments arguments_object {
|
||||
.argc = 0,
|
||||
.argv = nullptr,
|
||||
.strings = arguments
|
||||
};
|
||||
|
||||
StringView name = command.argv.first();
|
||||
|
||||
|
@ -1271,7 +1272,7 @@ bool Shell::run_builtin(const AST::Command& command, NonnullRefPtrVector<AST::Re
|
|||
|
||||
#define __ENUMERATE_SHELL_BUILTIN(builtin) \
|
||||
if (name == #builtin) { \
|
||||
retval = builtin_##builtin(argv.size() - 1, argv.data()); \
|
||||
retval = TRY(builtin_##builtin(arguments_object)); \
|
||||
if (!has_error(ShellError::None)) \
|
||||
raise_error(m_error, m_error_description, command.position); \
|
||||
fflush(stdout); \
|
||||
|
@ -1285,7 +1286,7 @@ bool Shell::run_builtin(const AST::Command& command, NonnullRefPtrVector<AST::Re
|
|||
return false;
|
||||
}
|
||||
|
||||
int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
||||
ErrorOr<int> Shell::builtin_argsparser_parse(Main::Arguments arguments)
|
||||
{
|
||||
// argsparser_parse
|
||||
// --add-option variable [--type (bool | string | i32 | u32 | double | size)] --help-string "" --long-name "" --short-name "" [--value-name "" <if not --type bool>] --list
|
||||
|
@ -1298,7 +1299,7 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
|
||||
Core::ArgsParser user_parser;
|
||||
|
||||
Vector<char const*> arguments;
|
||||
Vector<char const*> descriptors;
|
||||
Variant<Core::ArgsParser::Option, Core::ArgsParser::Arg, Empty> current;
|
||||
DeprecatedString current_variable;
|
||||
// if max > 1 or min < 1, or explicit `--list`.
|
||||
|
@ -1314,51 +1315,53 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
|
||||
auto type = Type::String;
|
||||
|
||||
auto try_convert = [](StringView value, Type type) -> Optional<RefPtr<AST::Value>> {
|
||||
auto try_convert = [](StringView value, Type type) -> ErrorOr<Optional<RefPtr<AST::Value>>> {
|
||||
switch (type) {
|
||||
case Type::Bool:
|
||||
return AST::make_ref_counted<AST::StringValue>(String::from_utf8("true"sv).release_value_but_fixme_should_propagate_errors());
|
||||
return AST::make_ref_counted<AST::StringValue>(TRY(String::from_utf8("true"sv)));
|
||||
case Type::String:
|
||||
return AST::make_ref_counted<AST::StringValue>(String::from_utf8(value).release_value_but_fixme_should_propagate_errors());
|
||||
return AST::make_ref_counted<AST::StringValue>(TRY(String::from_utf8(value)));
|
||||
case Type::I32:
|
||||
if (auto number = value.to_int(); number.has_value())
|
||||
return AST::make_ref_counted<AST::StringValue>(String::number(*number).release_value_but_fixme_should_propagate_errors());
|
||||
return AST::make_ref_counted<AST::StringValue>(TRY(String::number(*number)));
|
||||
|
||||
warnln("Invalid value for type i32: {}", value);
|
||||
return {};
|
||||
return OptionalNone {};
|
||||
case Type::U32:
|
||||
case Type::Size:
|
||||
if (auto number = value.to_uint(); number.has_value())
|
||||
return AST::make_ref_counted<AST::StringValue>(String::number(*number).release_value_but_fixme_should_propagate_errors());
|
||||
return AST::make_ref_counted<AST::StringValue>(TRY(String::number(*number)));
|
||||
|
||||
warnln("Invalid value for type u32|size: {}", value);
|
||||
return {};
|
||||
return OptionalNone {};
|
||||
case Type::Double: {
|
||||
DeprecatedString string = value;
|
||||
char* endptr = nullptr;
|
||||
auto number = strtod(string.characters(), &endptr);
|
||||
if (endptr != string.characters() + string.length()) {
|
||||
warnln("Invalid value for type double: {}", value);
|
||||
return {};
|
||||
return OptionalNone {};
|
||||
}
|
||||
|
||||
return AST::make_ref_counted<AST::StringValue>(String::number(number).release_value_but_fixme_should_propagate_errors());
|
||||
return AST::make_ref_counted<AST::StringValue>(TRY(String::number(number)));
|
||||
}
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
};
|
||||
|
||||
auto enlist = [&](auto name, auto value) -> NonnullRefPtr<AST::Value> {
|
||||
auto enlist = [&](auto name, auto value) -> ErrorOr<NonnullRefPtr<AST::Value>> {
|
||||
auto variable = lookup_local_variable(name);
|
||||
if (variable) {
|
||||
auto list = const_cast<AST::Value&>(*variable).resolve_as_list(*this).release_value_but_fixme_should_propagate_errors();
|
||||
auto new_value = value->resolve_as_string(*this).release_value_but_fixme_should_propagate_errors();
|
||||
auto list = TRY(const_cast<AST::Value&>(*variable).resolve_as_list(*this));
|
||||
auto new_value = TRY(value->resolve_as_string(*this));
|
||||
list.append(move(new_value));
|
||||
return make_ref_counted<AST::ListValue>(move(list));
|
||||
return try_make_ref_counted<AST::ListValue>(move(list));
|
||||
}
|
||||
return *value;
|
||||
};
|
||||
|
||||
// FIXME: We cannot return ErrorOr<T> from Core::ArgsParser::Option::accept_value(), fix the MUST's here whenever that function is ErrorOr-aware.
|
||||
auto commit = [&] {
|
||||
return current.visit(
|
||||
[&](Core::ArgsParser::Option& option) {
|
||||
|
@ -1367,11 +1370,11 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
return false;
|
||||
}
|
||||
option.accept_value = [&, current_variable, treat_arg_as_list, type](auto value) {
|
||||
auto result = try_convert({ value, strlen(value) }, type);
|
||||
auto result = MUST(try_convert({ value, strlen(value) }, type));
|
||||
if (result.has_value()) {
|
||||
auto value = result.release_value();
|
||||
if (treat_arg_as_list)
|
||||
value = enlist(current_variable, move(value));
|
||||
value = MUST(enlist(current_variable, move(value)));
|
||||
this->set_local_variable(current_variable, move(value), true);
|
||||
return true;
|
||||
}
|
||||
|
@ -1389,11 +1392,11 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
return false;
|
||||
}
|
||||
arg.accept_value = [&, current_variable, treat_arg_as_list, type](auto value) {
|
||||
auto result = try_convert({ value, strlen(value) }, type);
|
||||
auto result = MUST(try_convert({ value, strlen(value) }, type));
|
||||
if (result.has_value()) {
|
||||
auto value = result.release_value();
|
||||
if (treat_arg_as_list)
|
||||
value = enlist(current_variable, move(value));
|
||||
value = MUST(enlist(current_variable, move(value)));
|
||||
this->set_local_variable(current_variable, move(value), true);
|
||||
return true;
|
||||
}
|
||||
|
@ -1412,7 +1415,7 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
|
||||
parser.add_option(Core::ArgsParser::Option {
|
||||
.argument_mode = Core::ArgsParser::OptionArgumentMode::None,
|
||||
.help_string = "Stop processing arguments after a non-argument parameter is seen",
|
||||
.help_string = "Stop processing descriptors after a non-argument parameter is seen",
|
||||
.long_name = "stop-on-first-non-option",
|
||||
.accept_value = [&](auto) {
|
||||
user_parser.set_stop_on_first_non_option(true);
|
||||
|
@ -1496,8 +1499,12 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (type == Type::Bool)
|
||||
set_local_variable(current_variable, make_ref_counted<AST::StringValue>(String::from_utf8("false"sv).release_value_but_fixme_should_propagate_errors()), true);
|
||||
if (type == Type::Bool) {
|
||||
set_local_variable(
|
||||
current_variable,
|
||||
make_ref_counted<AST::StringValue>(MUST(String::from_utf8("false"sv))),
|
||||
true);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
@ -1616,7 +1623,7 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
});
|
||||
parser.add_option(Core::ArgsParser::Option {
|
||||
.argument_mode = Core::ArgsParser::OptionArgumentMode::Required,
|
||||
.help_string = "Set the minimum required number of positional arguments for the argument being described",
|
||||
.help_string = "Set the minimum required number of positional descriptors for the argument being described",
|
||||
.long_name = "min",
|
||||
.value_name = "n",
|
||||
.accept_value = [&](auto value) {
|
||||
|
@ -1644,7 +1651,7 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
});
|
||||
parser.add_option(Core::ArgsParser::Option {
|
||||
.argument_mode = Core::ArgsParser::OptionArgumentMode::Required,
|
||||
.help_string = "Set the maximum required number of positional arguments for the argument being described",
|
||||
.help_string = "Set the maximum required number of positional descriptors for the argument being described",
|
||||
.long_name = "max",
|
||||
.value_name = "n",
|
||||
.accept_value = [&](auto value) {
|
||||
|
@ -1687,15 +1694,15 @@ int Shell::builtin_argsparser_parse(int argc, char const** argv)
|
|||
return true;
|
||||
},
|
||||
});
|
||||
parser.add_positional_argument(arguments, "Arguments to parse via the described ArgsParser configuration", "arg", Core::ArgsParser::Required::No);
|
||||
parser.add_positional_argument(descriptors, "Arguments to parse via the described ArgsParser configuration", "arg", Core::ArgsParser::Required::No);
|
||||
|
||||
if (!parser.parse(argc, const_cast<char* const*>(argv), Core::ArgsParser::FailureBehavior::Ignore))
|
||||
if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::Ignore))
|
||||
return 2;
|
||||
|
||||
if (!commit())
|
||||
return 2;
|
||||
|
||||
if (!user_parser.parse(static_cast<int>(arguments.size()), const_cast<char* const*>(arguments.data()), Core::ArgsParser::FailureBehavior::Ignore))
|
||||
if (!user_parser.parse(static_cast<int>(descriptors.size()), const_cast<char* const*>(descriptors.data()), Core::ArgsParser::FailureBehavior::Ignore))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -700,7 +700,7 @@ ErrorOr<RefPtr<Job>> Shell::run_command(const AST::Command& command)
|
|||
for (auto& redirection : command.redirections)
|
||||
TRY(resolve_redirection(redirection));
|
||||
|
||||
if (int local_return_code = 0; command.should_wait && run_builtin(command, rewirings, local_return_code)) {
|
||||
if (int local_return_code = 0; command.should_wait && TRY(run_builtin(command, rewirings, local_return_code))) {
|
||||
last_return_code = local_return_code;
|
||||
for (auto& next_in_chain : command.next_chain)
|
||||
run_tail(command, next_in_chain, *last_return_code);
|
||||
|
@ -791,7 +791,7 @@ ErrorOr<RefPtr<Job>> Shell::run_command(const AST::Command& command)
|
|||
_exit(last_return_code.value_or(0));
|
||||
}
|
||||
|
||||
if (int local_return_code = 0; run_builtin(command, {}, local_return_code))
|
||||
if (int local_return_code = 0; TRY(run_builtin(command, {}, local_return_code)))
|
||||
_exit(local_return_code);
|
||||
|
||||
if (int local_return_code = 0; invoke_function(command, local_return_code))
|
||||
|
@ -877,6 +877,24 @@ ErrorOr<RefPtr<Job>> Shell::run_command(const AST::Command& command)
|
|||
return *job;
|
||||
}
|
||||
|
||||
ErrorOr<void> Shell::execute_process(Span<StringView> argv)
|
||||
{
|
||||
Vector<DeprecatedString> strings;
|
||||
Vector<char const*> args;
|
||||
TRY(strings.try_ensure_capacity(argv.size()));
|
||||
TRY(args.try_ensure_capacity(argv.size() + 1));
|
||||
|
||||
for (auto& entry : argv) {
|
||||
strings.unchecked_append(entry);
|
||||
args.unchecked_append(strings.last().characters());
|
||||
}
|
||||
|
||||
args.append(nullptr);
|
||||
|
||||
// NOTE: noreturn.
|
||||
execute_process(move(args));
|
||||
}
|
||||
|
||||
void Shell::execute_process(Vector<char const*>&& argv)
|
||||
{
|
||||
for (auto& promise : m_active_promises) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <LibCore/Notifier.h>
|
||||
#include <LibCore/Object.h>
|
||||
#include <LibLine/Editor.h>
|
||||
#include <LibMain/Main.h>
|
||||
#include <termios.h>
|
||||
|
||||
#define ENUMERATE_SHELL_BUILTINS() \
|
||||
|
@ -153,7 +154,7 @@ public:
|
|||
ErrorOr<RefPtr<Job>> run_command(const AST::Command&);
|
||||
NonnullRefPtrVector<Job> run_commands(Vector<AST::Command>&);
|
||||
bool run_file(DeprecatedString const&, bool explicitly_invoked = true);
|
||||
bool run_builtin(const AST::Command&, NonnullRefPtrVector<AST::Rewiring> const&, int& retval);
|
||||
ErrorOr<bool> run_builtin(const AST::Command&, NonnullRefPtrVector<AST::Rewiring> const&, int& retval);
|
||||
bool has_builtin(StringView) const;
|
||||
RefPtr<AST::Node> run_immediate_function(StringView name, AST::ImmediateExpression& invoking_node, NonnullRefPtrVector<AST::Node> const&);
|
||||
static bool has_immediate_function(StringView);
|
||||
|
@ -417,6 +418,7 @@ private:
|
|||
void run_tail(const AST::Command&, const AST::NodeWithAction&, int head_exit_code);
|
||||
|
||||
[[noreturn]] void execute_process(Vector<char const*>&& argv);
|
||||
ErrorOr<void> execute_process(Span<StringView> argv);
|
||||
|
||||
virtual void custom_event(Core::CustomEvent&) override;
|
||||
|
||||
|
@ -430,7 +432,7 @@ private:
|
|||
RefPtr<AST::Node> immediate_length_impl(AST::ImmediateExpression& invoking_node, NonnullRefPtrVector<AST::Node> const&, bool across);
|
||||
|
||||
#define __ENUMERATE_SHELL_BUILTIN(builtin) \
|
||||
int builtin_##builtin(int argc, char const** argv);
|
||||
ErrorOr<int> builtin_##builtin(Main::Arguments);
|
||||
|
||||
ENUMERATE_SHELL_BUILTINS();
|
||||
|
||||
|
|
Loading…
Reference in a new issue