add option --handlers to functions to display function hooks

This commit is contained in:
Benoit Hamon 2018-01-31 18:47:23 +01:00 committed by ridiculousfish
parent 7764f27170
commit 3819437e0e
3 changed files with 116 additions and 2 deletions

View file

@ -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());

View file

@ -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<int, wcstring> 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<int, wcstring>::iterator it = events_map.find(type);
if (it != events_map.end())
return it->second;
return L"";
}
int wcs2event(wcstring const &event) {
for (std::map<int, wcstring>::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<shared_ptr<event_t>> tmp = s_event_handlers;
std::sort(tmp.begin(), tmp.end(),
[](const shared_ptr<event_t> &e1, const shared_ptr<event_t> &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<event_t> &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, );

View file

@ -8,10 +8,12 @@
#include <unistd.h>
#include <map>
#include <memory>
#include <vector>
#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);