From 45c429853ac1e2626edfe38f96613216d450ec0e Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 15 May 2023 14:59:26 +0100 Subject: ps: Allow `-q` option multiple times, and separated by spaces or commas Several differences here: - Passing `-q` multiple times will add them together, instead of the last one overwriting the previous ones. - `-q` PIDs can be separated by commas as well as spaces. - We check that the PIDs are integers while parsing the arguments, instead of later on. The "parse a list of things as an option" is extracted into a helper function, because we're going to want the same logic for `-g`, `-G`, `-p`, `-t`, `-u`, and `-U`. --- Userland/Utilities/ps.cpp | 52 +++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'Userland/Utilities') diff --git a/Userland/Utilities/ps.cpp b/Userland/Utilities/ps.cpp index 75195171cd..33b5c36502 100644 --- a/Userland/Utilities/ps.cpp +++ b/Userland/Utilities/ps.cpp @@ -30,6 +30,28 @@ static ErrorOr determine_tty_pseudo_name() return "n/a"_short_string; } +template +Core::ArgsParser::Option make_list_option(Vector& value_list, char const* help_string, char const* long_name, char short_name, char const* value_name, ParseValue parse_value) +{ + return Core::ArgsParser::Option { + .argument_mode = Core::ArgsParser::OptionArgumentMode::Required, + .help_string = help_string, + .long_name = long_name, + .short_name = short_name, + .value_name = value_name, + .accept_value = [&](StringView s) { + auto parts = s.split_view_if([](char c) { return c == ',' || c == ' '; }); + for (auto const& part : parts) { + auto value = parse_value(part); + if (!value.has_value()) + return false; + value_list.append(value.value()); + } + return true; + }, + }; +} + ErrorOr serenity_main(Main::Arguments arguments) { TRY(Core::System::pledge("stdio rpath tty")); @@ -56,14 +78,19 @@ ErrorOr serenity_main(Main::Arguments arguments) bool every_process_flag = false; bool every_terminal_process_flag = false; bool full_format_flag = false; - StringView pid_list; + Vector pid_list; Core::ArgsParser args_parser; args_parser.add_option(every_terminal_process_flag, "Show every process associated with terminals", nullptr, 'a'); args_parser.add_option(every_process_flag, "Show every process", nullptr, 'A'); args_parser.add_option(every_process_flag, "Show every process (Equivalent to -A)", nullptr, 'e'); args_parser.add_option(full_format_flag, "Full format", nullptr, 'f'); - args_parser.add_option(pid_list, "A comma-separated list of PIDs. Only processes matching those PIDs will be selected", nullptr, 'q', "pid-list"); + args_parser.add_option(make_list_option(pid_list, "A comma- or space-separated list of PIDs. Only processes matching those PIDs will be selected", nullptr, 'q', "pid-list", [](StringView pid_string) { + auto pid = pid_string.to_int(); + if (!pid.has_value()) + warnln("Could not parse '{}' as a PID.", pid_string); + return pid; + })); args_parser.parse(arguments); Vector columns; @@ -105,26 +132,11 @@ ErrorOr serenity_main(Main::Arguments arguments) if (!pid_list.is_empty()) { every_process_flag = true; - auto string_parts = pid_list.split_view(','); - Vector selected_pids; - selected_pids.ensure_capacity(string_parts.size()); - - for (size_t i = 0; i < string_parts.size(); i++) { - auto pid = string_parts[i].to_int(); - - if (!pid.has_value()) { - warnln("Invalid value for -q: {}", pid_list); - warnln("Could not parse '{}' as a PID.", string_parts[i]); - return 1; - } - - selected_pids.append(pid.value()); - } - processes.remove_all_matching([&](auto& a) { return selected_pids.find(a.pid) == selected_pids.end(); }); + processes.remove_all_matching([&](auto& a) { return !pid_list.contains_slow(a.pid); }); - auto processes_sort_predicate = [&selected_pids](auto& a, auto& b) { - return selected_pids.find_first_index(a.pid).value() < selected_pids.find_first_index(b.pid).value(); + auto processes_sort_predicate = [&pid_list](auto& a, auto& b) { + return pid_list.find_first_index(a.pid).value() < pid_list.find_first_index(b.pid).value(); }; quick_sort(processes, processes_sort_predicate); } else { -- cgit v1.2.3