summaryrefslogtreecommitdiff
path: root/Userland/Utilities
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@serenityos.org>2023-05-15 14:59:26 +0100
committerAndreas Kling <kling@serenityos.org>2023-05-16 12:54:18 +0200
commit45c429853ac1e2626edfe38f96613216d450ec0e (patch)
tree15c7ae42ab41e92d8275e3be7d41ed9d84a1ab63 /Userland/Utilities
parenta6e701a67bf9d21ede5ccecbce3b3c9fef6ce8c4 (diff)
downloadserenity-45c429853ac1e2626edfe38f96613216d450ec0e.zip
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`.
Diffstat (limited to 'Userland/Utilities')
-rw-r--r--Userland/Utilities/ps.cpp52
1 files changed, 32 insertions, 20 deletions
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<String> determine_tty_pseudo_name()
return "n/a"_short_string;
}
+template<typename Value, typename ParseValue>
+Core::ArgsParser::Option make_list_option(Vector<Value>& 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<int> serenity_main(Main::Arguments arguments)
{
TRY(Core::System::pledge("stdio rpath tty"));
@@ -56,14 +78,19 @@ ErrorOr<int> 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_t> 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<Column> columns;
@@ -105,26 +132,11 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
if (!pid_list.is_empty()) {
every_process_flag = true;
- auto string_parts = pid_list.split_view(',');
- Vector<pid_t> 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 {