From 5cb994d4dd6a1a43d625769e2a1823fb3704fb79 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Fri, 13 Oct 2023 03:10:31 +0330 Subject: [PATCH] Shell: Minimally implement the 'set' builtin This only implements the printing and argv setting behaviours. --- Userland/Shell/Builtin.cpp | 100 +++++++++++++++++++++++++++++++------ Userland/Shell/Shell.h | 9 ++-- 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/Userland/Shell/Builtin.cpp b/Userland/Shell/Builtin.cpp index 0315919edb..e148050b08 100644 --- a/Userland/Shell/Builtin.cpp +++ b/Userland/Shell/Builtin.cpp @@ -332,6 +332,26 @@ ErrorOr Shell::builtin_bg(Main::Arguments arguments) return 0; } +ErrorOr Shell::serialize_function_definition(ShellFunction const& fn) const +{ + StringBuilder builder; + builder.append(fn.name); + builder.append('('); + for (size_t i = 0; i < fn.arguments.size(); i++) { + builder.append(fn.arguments[i]); + if (i != fn.arguments.size() - 1) + builder.append(' '); + } + builder.append(") {\n"sv); + if (fn.body) { + auto formatter = Formatter(*fn.body); + builder.append(formatter.format()); + } + builder.append("\n}"sv); + + return builder.to_string(); +} + ErrorOr Shell::builtin_type(Main::Arguments arguments) { Vector commands; @@ -359,22 +379,8 @@ ErrorOr Shell::builtin_type(Main::Arguments arguments) auto fn = function.value(); printf("%s is a function\n", command.characters()); if (!dont_show_function_source) { - StringBuilder builder; - builder.append(fn.name); - builder.append('('); - for (size_t i = 0; i < fn.arguments.size(); i++) { - builder.append(fn.arguments[i]); - if (!(i == fn.arguments.size() - 1)) - builder.append(' '); - } - builder.append(") {\n"sv); - if (fn.body) { - auto formatter = Formatter(*fn.body); - builder.append(formatter.format()); - printf("%s\n}\n", builder.to_deprecated_string().characters()); - } else { - printf("%s\n}\n", builder.to_deprecated_string().characters()); - } + auto source = TRY(serialize_function_definition(fn)); + outln("{}", source); } continue; } @@ -1289,6 +1295,68 @@ ErrorOr Shell::builtin_unset(Main::Arguments arguments) return 0; } +ErrorOr Shell::builtin_set(Main::Arguments arguments) +{ + if (arguments.strings.size() == 1) { + HashMap vars; + + StringBuilder builder; + for (auto& frame : m_local_frames) { + for (auto& var : frame->local_variables) { + builder.join(" "sv, TRY(var.value->resolve_as_list(*this))); + vars.set(TRY(String::from_deprecated_string(var.key)), TRY(builder.to_string())); + builder.clear(); + } + } + + struct Variable { + StringView name; + String value; + }; + + Vector variables; + variables.ensure_capacity(vars.size()); + + for (auto& var : vars) + variables.unchecked_append({ var.key, var.value }); + + Vector functions; + functions.ensure_capacity(m_functions.size()); + for (auto& function : m_functions) + functions.unchecked_append(TRY(serialize_function_definition(function.value))); + + quick_sort(variables, [](auto& a, auto& b) { return a.name < b.name; }); + quick_sort(functions, [](auto& a, auto& b) { return a < b; }); + + for (auto& var : variables) + outln("{}={}", var.name, escape_token(var.value)); + + for (auto& fn : functions) + outln("{}", fn); + + return 0; + } + + Vector argv_to_set; + + Core::ArgsParser parser; + parser.set_stop_on_first_non_option(true); + parser.add_positional_argument(argv_to_set, "List of arguments", "arg", Core::ArgsParser::Required::No); + + if (!parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage)) + return 1; + + if (!argv_to_set.is_empty() || arguments.strings.last() == "--"sv) { + Vector argv; + argv.ensure_capacity(argv_to_set.size()); + for (auto& arg : argv_to_set) + argv.unchecked_append(TRY(String::from_utf8(arg))); + set_local_variable("ARGV", AST::make_ref_counted(move(argv))); + } + + return 0; +} + ErrorOr Shell::builtin_not(Main::Arguments arguments) { Vector args; diff --git a/Userland/Shell/Shell.h b/Userland/Shell/Shell.h index ac56b6b7c5..2779446625 100644 --- a/Userland/Shell/Shell.h +++ b/Userland/Shell/Shell.h @@ -38,6 +38,7 @@ __ENUMERATE_SHELL_BUILTIN(glob, InAllModes) \ __ENUMERATE_SHELL_BUILTIN(unalias, InAllModes) \ __ENUMERATE_SHELL_BUILTIN(unset, InAllModes) \ + __ENUMERATE_SHELL_BUILTIN(set, InAllModes) \ __ENUMERATE_SHELL_BUILTIN(history, InAllModes) \ __ENUMERATE_SHELL_BUILTIN(umask, InAllModes) \ __ENUMERATE_SHELL_BUILTIN(not, InAllModes) \ @@ -479,15 +480,17 @@ private: // clang-format on }; - bool m_should_ignore_jobs_on_next_exit { false }; - pid_t m_pid { 0 }; - struct ShellFunction { DeprecatedString name; Vector arguments; RefPtr body; }; + ErrorOr serialize_function_definition(ShellFunction const&) const; + + bool m_should_ignore_jobs_on_next_exit { false }; + pid_t m_pid { 0 }; + HashMap m_functions; Vector> m_local_frames; Promise::List m_active_promises;