diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp index c8433d0b2..5a51c3024 100644 --- a/src/builtin_functions.cpp +++ b/src/builtin_functions.cpp @@ -35,15 +35,18 @@ struct functions_cmd_opts_t { bool copy = false; bool report_metadata = false; bool verbose = false; + bool handlers = false; + wchar_t *handlers_type = NULL; wchar_t *description = NULL; }; -static const wchar_t *short_options = L":Dacehnqv"; +static const wchar_t *short_options = L":HDacehnqv"; static const struct woption long_options[] = { {L"erase", no_argument, NULL, 'e'}, {L"description", required_argument, NULL, 'd'}, {L"names", no_argument, NULL, 'n'}, {L"all", no_argument, NULL, 'a'}, {L"help", no_argument, NULL, 'h'}, {L"query", no_argument, NULL, 'q'}, {L"copy", no_argument, NULL, 'c'}, {L"details", no_argument, NULL, 'D'}, - {L"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0}}; + {L"verbose", no_argument, NULL, 'v'}, {L"handlers", no_argument, NULL, 'H'}, + {L"handlers-type", required_argument, NULL, 't'}, {NULL, 0, NULL, 0}}; static int parse_cmd_opts(functions_cmd_opts_t &opts, int *optind, //!OCLINT(high ncss method) int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) { @@ -88,6 +91,15 @@ static int parse_cmd_opts(functions_cmd_opts_t &opts, int *optind, //!OCLINT(hi opts.copy = true; break; } + case 'H': { + opts.handlers = true; + break; + } + case 't': { + opts.handlers_type = w.woptarg; + opts.handlers = true; + break; + } case ':': { builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]); return STATUS_INVALID_ARGS; @@ -311,6 +323,20 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { return report_function_metadata(funcname, opts.verbose, streams, false); } + if (opts.handlers) { + int type = -1; + if (opts.handlers_type) { + type = wcs2event(opts.handlers_type); + if (type == -1) { + streams.err.append_format(_(L"%ls: Expected generic | variable | signal | exit | job-id for --handlers_type\n"), + cmd); + return STATUS_INVALID_ARGS; + } + } + event_print(streams, type); + return STATUS_CMD_OK; + } + if (opts.list || argc == optind) { wcstring_list_t names = function_get_names(opts.show_hidden); std::sort(names.begin(), names.end()); diff --git a/src/event.cpp b/src/event.cpp index 1afbfe2e7..9528de4b7 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -50,6 +50,14 @@ static event_list_t s_event_handlers; /// List of events that have been sent but have not yet been delivered because they are blocked. static event_list_t blocked; +static std::map events_map = { + {EVENT_SIGNAL, L"signal"}, + {EVENT_VARIABLE, L"variable"}, + {EVENT_EXIT, L"exit"}, + {EVENT_JOB_ID, L"job-id"}, + {EVENT_GENERIC, L"generic"} +}; + /// Variables (one per signal) set when a signal is observed. This is inspected by a signal handler. static volatile bool s_observed_signals[NSIG] = {}; static void set_signal_observed(int sig, bool val) { @@ -448,6 +456,74 @@ void event_fire(const event_t *event) { } } +wcstring event2wcs(int type) { + std::map::iterator it = events_map.find(type); + + if (it != events_map.end()) + return it->second; + return L""; +} + +int wcs2event(wcstring const &event) { + for (std::map::iterator it = events_map.begin(); it != events_map.end(); ++it) { + if (it->second == event) + return it->first; + } + return -1; +} + +void event_print(io_streams_t &streams, int event_type) { + std::vector> tmp = s_event_handlers; + std::sort(tmp.begin(), tmp.end(), + [](const shared_ptr &e1, const shared_ptr &e2) { + if (e1->type == e2->type) { + switch (e1->type) { + case EVENT_SIGNAL: + return e1->param1.signal < e2->param1.signal; + case EVENT_JOB_ID: + return e1->param1.job_id < e2->param1.job_id; + case EVENT_VARIABLE: + case EVENT_ANY: + case EVENT_GENERIC: + return e1->str_param1 < e2->str_param1; + } + } else { + return e1->type < e2->type; + } + }); + + int type = -1; + for (const shared_ptr &evt : tmp) { + if (event_type == -1 || event_type == evt->type) { + if (evt->type != type) { + if (type != -1) + streams.out.append(L"\n"); + type = evt->type; + streams.out.append_format(L"Event %ls\n", event2wcs(evt->type).c_str()); + } + switch (evt->type) { + case EVENT_SIGNAL: + streams.out.append_format(L"%ls %ls\n", sig2wcs(evt->param1.signal), + evt->function_name.c_str()); + break; + case EVENT_JOB_ID: + streams.out.append_format(L"%d %ls\n", evt->param1, + evt->function_name.c_str()); + break; + case EVENT_VARIABLE: + case EVENT_GENERIC: + streams.out.append_format(L"%ls %ls\n", evt->str_param1.c_str(), + evt->function_name.c_str()); + break; + default: + streams.out.append_format(L"%ls\n", evt->function_name.c_str()); + break; + + } + } + } +} + void event_fire_generic(const wchar_t *name, wcstring_list_t *args) { CHECK(name, ); diff --git a/src/event.h b/src/event.h index 6133cfe16..d26d133ea 100644 --- a/src/event.h +++ b/src/event.h @@ -8,10 +8,12 @@ #include +#include #include #include #include "common.h" +#include "io.h" /// The signal number that is used to match any signal. #define EVENT_ANY_SIGNAL -1 @@ -125,6 +127,16 @@ void event_fire(const event_t *event); /// May be called from signal handlers void event_fire_signal(int signal); +/// Convert a string to the corresponding type +int wcs2event(wcstring const &event); + +/// Convert a type to the corresponding string +wcstring event2wcs(int type); + +/// Called by builtin functions +/// Dumped all events +void event_print(io_streams_t &streams, int event_type); + /// Returns a string describing the specified event. wcstring event_get_desc(const event_t &e);