mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 14:29:16 +08:00
Merge branch 'event-bug-test' of git://github.com/JanKanis/fish-shell into JanKanis-event-bug-test
This commit is contained in:
commit
8a66ba6c35
14
builtin.cpp
14
builtin.cpp
|
@ -1009,15 +1009,15 @@ static int builtin_emit(parser_t &parser, wchar_t **argv)
|
|||
|
||||
}
|
||||
|
||||
for (; woptind < argc; woptind++)
|
||||
{
|
||||
event_fire_generic(argv[woptind]);
|
||||
if(!argv[woptind]) {
|
||||
append_format(stderr_buffer, L"%ls: expected event name\n", argv[0]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
wchar_t *eventname = argv[woptind];
|
||||
wcstring_list_t args(argv + woptind + 1, argv + argc);
|
||||
event_fire_generic(eventname, &args);
|
||||
|
||||
return STATUS_BUILTIN_OK;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1099,7 +1099,7 @@ static void functions_def(const wcstring &name, wcstring &out)
|
|||
search.function_name = name;
|
||||
|
||||
std::vector<event_t *> ev;
|
||||
event_get(&search, &ev);
|
||||
event_get(search, &ev);
|
||||
|
||||
out.append(L"function ");
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
\section emit emit - Emit a generic event
|
||||
|
||||
\subsection block-synopsis Synopsis
|
||||
<tt>emit EVENT_NAME</tt>
|
||||
<tt>emit EVENT_NAME [ARGUMENTS...]</tt>
|
||||
|
||||
\subsection emit-description Description
|
||||
|
||||
The emit builtin fires a generic fish event. Such events can be caught by special functions called event handlers.
|
||||
The emit builtin fires a generic fish event. Such events can be caught by special functions called event handlers. The arguments are passed to the event handlers as function arguments.
|
||||
|
||||
\subsection emit-example Example
|
||||
|
||||
|
@ -13,7 +13,8 @@ The following code first defines an event handler for the generic
|
|||
event named 'test_event', and then emits an event of that type.
|
||||
|
||||
<pre>function event_test --on-event test_event
|
||||
echo event test!!!
|
||||
echo event test: $argv
|
||||
end
|
||||
|
||||
emit test_event</pre>
|
||||
emit test_event something
|
||||
</pre>
|
||||
|
|
24
env.cpp
24
env.cpp
|
@ -415,12 +415,10 @@ static void universal_callback(fish_message_type_t type,
|
|||
mark_changed_exported();
|
||||
|
||||
event_t ev = event_t::variable_event(name);
|
||||
ev.arguments.reset(new wcstring_list_t());
|
||||
ev.arguments->push_back(L"VARIABLE");
|
||||
ev.arguments->push_back(str);
|
||||
ev.arguments->push_back(name);
|
||||
ev.arguments.push_back(L"VARIABLE");
|
||||
ev.arguments.push_back(str);
|
||||
ev.arguments.push_back(name);
|
||||
event_fire(&ev);
|
||||
ev.arguments.reset(NULL);
|
||||
}
|
||||
|
||||
if (name)
|
||||
|
@ -961,15 +959,13 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode)
|
|||
if (!is_universal)
|
||||
{
|
||||
event_t ev = event_t::variable_event(key);
|
||||
ev.arguments.reset(new wcstring_list_t);
|
||||
ev.arguments->push_back(L"VARIABLE");
|
||||
ev.arguments->push_back(L"SET");
|
||||
ev.arguments->push_back(key);
|
||||
ev.arguments.push_back(L"VARIABLE");
|
||||
ev.arguments.push_back(L"SET");
|
||||
ev.arguments.push_back(key);
|
||||
|
||||
// debug( 1, L"env_set: fire events on variable %ls", key );
|
||||
event_fire(&ev);
|
||||
// debug( 1, L"env_set: return from event firing" );
|
||||
ev.arguments.reset(NULL);
|
||||
}
|
||||
|
||||
react_to_variable_change(key);
|
||||
|
@ -1048,14 +1044,12 @@ int env_remove(const wcstring &key, int var_mode)
|
|||
if (try_remove(first_node, key.c_str(), var_mode))
|
||||
{
|
||||
event_t ev = event_t::variable_event(key);
|
||||
ev.arguments.reset(new wcstring_list_t);
|
||||
ev.arguments->push_back(L"VARIABLE");
|
||||
ev.arguments->push_back(L"ERASE");
|
||||
ev.arguments->push_back(key);
|
||||
ev.arguments.push_back(L"VARIABLE");
|
||||
ev.arguments.push_back(L"ERASE");
|
||||
ev.arguments.push_back(key);
|
||||
|
||||
event_fire(&ev);
|
||||
|
||||
ev.arguments.reset(NULL);
|
||||
erased = 1;
|
||||
}
|
||||
}
|
||||
|
|
250
event.cpp
250
event.cpp
|
@ -25,6 +25,7 @@
|
|||
#include "event.h"
|
||||
#include "signal.h"
|
||||
|
||||
|
||||
/**
|
||||
Number of signals that can be queued before an overflow occurs
|
||||
*/
|
||||
|
@ -86,137 +87,120 @@ static event_list_t blocked;
|
|||
they must name the same function.
|
||||
|
||||
*/
|
||||
static int event_match(const event_t *classv, const event_t *instance)
|
||||
static int event_match(const event_t &classv, const event_t &instance)
|
||||
{
|
||||
|
||||
/* If the function names are both non-empty and different, then it's not a match */
|
||||
if (! classv->function_name.empty() &&
|
||||
! instance->function_name.empty() &&
|
||||
classv->function_name != instance->function_name)
|
||||
if (! classv.function_name.empty() &&
|
||||
! instance.function_name.empty() &&
|
||||
classv.function_name != instance.function_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (classv->type == EVENT_ANY)
|
||||
if (classv.type == EVENT_ANY)
|
||||
return 1;
|
||||
|
||||
if (classv->type != instance->type)
|
||||
if (classv.type != instance.type)
|
||||
return 0;
|
||||
|
||||
|
||||
switch (classv->type)
|
||||
switch (classv.type)
|
||||
{
|
||||
|
||||
case EVENT_SIGNAL:
|
||||
if (classv->param1.signal == EVENT_ANY_SIGNAL)
|
||||
if (classv.param1.signal == EVENT_ANY_SIGNAL)
|
||||
return 1;
|
||||
return classv->param1.signal == instance->param1.signal;
|
||||
return classv.param1.signal == instance.param1.signal;
|
||||
|
||||
case EVENT_VARIABLE:
|
||||
return instance->str_param1 == classv->str_param1;
|
||||
return instance.str_param1 == classv.str_param1;
|
||||
|
||||
case EVENT_EXIT:
|
||||
if (classv->param1.pid == EVENT_ANY_PID)
|
||||
if (classv.param1.pid == EVENT_ANY_PID)
|
||||
return 1;
|
||||
return classv->param1.pid == instance->param1.pid;
|
||||
return classv.param1.pid == instance.param1.pid;
|
||||
|
||||
case EVENT_JOB_ID:
|
||||
return classv->param1.job_id == instance->param1.job_id;
|
||||
return classv.param1.job_id == instance.param1.job_id;
|
||||
|
||||
case EVENT_GENERIC:
|
||||
return instance->str_param1 == classv->str_param1;
|
||||
return instance.str_param1 == classv.str_param1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
This should never be reached
|
||||
*/
|
||||
debug(0, "Warning: Unreachable code reached in event_match in event.cpp\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create an identical copy of an event. Use deep copying, i.e. make
|
||||
duplicates of any strings used as well.
|
||||
*/
|
||||
static event_t *event_copy(const event_t *event, int copy_arguments)
|
||||
{
|
||||
event_t *e = new event_t(*event);
|
||||
|
||||
e->arguments.reset(new wcstring_list_t);
|
||||
if (copy_arguments && event->arguments.get() != NULL)
|
||||
{
|
||||
*(e->arguments) = *(event->arguments);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
Test if specified event is blocked
|
||||
*/
|
||||
static int event_is_blocked(event_t *e)
|
||||
static int event_is_blocked(const event_t &e)
|
||||
{
|
||||
block_t *block;
|
||||
parser_t &parser = parser_t::principal_parser();
|
||||
for (block = parser.current_block; block; block = block->outer)
|
||||
{
|
||||
if (event_block_list_blocks_type(block->event_blocks, e->type))
|
||||
if (event_block_list_blocks_type(block->event_blocks, e.type))
|
||||
return true;
|
||||
}
|
||||
return event_block_list_blocks_type(parser.global_event_blocks, e->type);
|
||||
return event_block_list_blocks_type(parser.global_event_blocks, e.type);
|
||||
}
|
||||
|
||||
wcstring event_get_desc(const event_t *e)
|
||||
wcstring event_get_desc(const event_t &e)
|
||||
{
|
||||
|
||||
CHECK(e, 0);
|
||||
|
||||
wcstring result;
|
||||
switch (e->type)
|
||||
switch (e.type)
|
||||
{
|
||||
|
||||
case EVENT_SIGNAL:
|
||||
result = format_string(_(L"signal handler for %ls (%ls)"), sig2wcs(e->param1.signal), signal_get_desc(e->param1.signal));
|
||||
result = format_string(_(L"signal handler for %ls (%ls)"), sig2wcs(e.param1.signal), signal_get_desc(e.param1.signal));
|
||||
break;
|
||||
|
||||
case EVENT_VARIABLE:
|
||||
result = format_string(_(L"handler for variable '%ls'"), e->str_param1.c_str());
|
||||
result = format_string(_(L"handler for variable '%ls'"), e.str_param1.c_str());
|
||||
break;
|
||||
|
||||
case EVENT_EXIT:
|
||||
if (e->param1.pid > 0)
|
||||
if (e.param1.pid > 0)
|
||||
{
|
||||
result = format_string(_(L"exit handler for process %d"), e->param1.pid);
|
||||
result = format_string(_(L"exit handler for process %d"), e.param1.pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
job_t *j = job_get_from_pid(-e->param1.pid);
|
||||
job_t *j = job_get_from_pid(-e.param1.pid);
|
||||
if (j)
|
||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr());
|
||||
else
|
||||
result = format_string(_(L"exit handler for job with process group %d"), -e->param1.pid);
|
||||
result = format_string(_(L"exit handler for job with process group %d"), -e.param1.pid);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EVENT_JOB_ID:
|
||||
{
|
||||
job_t *j = job_get(e->param1.job_id);
|
||||
job_t *j = job_get(e.param1.job_id);
|
||||
if (j)
|
||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr());
|
||||
else
|
||||
result = format_string(_(L"exit handler for job with job id %d"), e->param1.job_id);
|
||||
result = format_string(_(L"exit handler for job with job id %d"), e.param1.job_id);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_GENERIC:
|
||||
result = format_string(_(L"handler for generic event '%ls'"), e->str_param1.c_str());
|
||||
result = format_string(_(L"handler for generic event '%ls'"), e.str_param1.c_str());
|
||||
break;
|
||||
|
||||
default:
|
||||
result = format_string(_(L"Unknown event type"));
|
||||
result = format_string(_(L"Unknown event type '0x%x'"), e.type);
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -237,13 +221,82 @@ static void show_all_handlers(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
void event_add_handler(const event_t *event)
|
||||
/*
|
||||
Give a more condensed description of \c event compared to \c event_get_desc.
|
||||
It includes what function will fire if the \c event is an event handler.
|
||||
*/
|
||||
static wcstring event_desc_compact(const event_t &event) {
|
||||
wcstring res;
|
||||
wchar_t const *temp;
|
||||
int sig;
|
||||
switch(event.type) {
|
||||
case EVENT_ANY:
|
||||
res = L"EVENT_ANY";
|
||||
break;
|
||||
case EVENT_VARIABLE:
|
||||
if(event.str_param1.c_str()) {
|
||||
res = format_string(L"EVENT_VARIABLE($%ls)", event.str_param1.c_str());
|
||||
} else {
|
||||
res = L"EVENT_VARIABLE([any])";
|
||||
}
|
||||
break;
|
||||
case EVENT_SIGNAL:
|
||||
sig = event.param1.signal;
|
||||
if(sig == EVENT_ANY_SIGNAL) {
|
||||
temp = L"[all signals]";
|
||||
} else if(sig == 0) {
|
||||
temp = L"not set";
|
||||
} else {
|
||||
temp = sig2wcs(sig);
|
||||
}
|
||||
res = format_string(L"EVENT_SIGNAL(%ls)", temp);
|
||||
break;
|
||||
case EVENT_EXIT:
|
||||
if(event.param1.pid == EVENT_ANY_PID) {
|
||||
res = wcstring(L"EVENT_EXIT([all child processes])");
|
||||
} else if (event.param1.pid > 0) {
|
||||
res = format_string(L"EVENT_EXIT(pid %d)", event.param1.pid);
|
||||
} else {
|
||||
job_t *j = job_get_from_pid(-event.param1.pid);
|
||||
if (j)
|
||||
res = format_string(L"EVENT_EXIT(jobid %d: \"%ls\")", j->job_id, j->command_wcstr());
|
||||
else
|
||||
res = format_string(L"EVENT_EXIT(pgid %d)", -event.param1.pid);
|
||||
}
|
||||
break;
|
||||
case EVENT_JOB_ID:
|
||||
{
|
||||
job_t *j = job_get(event.param1.job_id);
|
||||
if (j)
|
||||
res = format_string(L"EVENT_JOB_ID(job %d: \"%ls\")", j->job_id, j->command_wcstr());
|
||||
else
|
||||
res = format_string(L"EVENT_JOB_ID(jobid %d)", event.param1.job_id);
|
||||
break;
|
||||
}
|
||||
case EVENT_GENERIC:
|
||||
res = format_string(L"EVENT_GENERIC(%ls)", event.str_param1.c_str());
|
||||
break;
|
||||
default:
|
||||
res = format_string(L"unknown/illegal event(%x)", event.type);
|
||||
}
|
||||
if(event.function_name.size()) {
|
||||
return format_string(L"%ls: \"%ls\"", res.c_str(), event.function_name.c_str());
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void event_add_handler(const event_t &event)
|
||||
{
|
||||
event_t *e;
|
||||
|
||||
CHECK(event,);
|
||||
if(debug_level >= 3) {
|
||||
wcstring desc = event_desc_compact(event);
|
||||
debug(3, "register: %ls\n", desc.c_str());
|
||||
}
|
||||
|
||||
e = event_copy(event, 0);
|
||||
e = new event_t(event);
|
||||
|
||||
if (e->type == EVENT_SIGNAL)
|
||||
{
|
||||
|
@ -256,13 +309,16 @@ void event_add_handler(const event_t *event)
|
|||
signal_unblock();
|
||||
}
|
||||
|
||||
void event_remove(event_t *criterion)
|
||||
void event_remove(const event_t &criterion)
|
||||
{
|
||||
|
||||
size_t i;
|
||||
event_list_t new_list;
|
||||
|
||||
CHECK(criterion,);
|
||||
if(debug_level >= 3) {
|
||||
wcstring desc = event_desc_compact(criterion);
|
||||
debug(3, "unregister: %ls\n", desc.c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
Because of concurrency issues (env_remove could remove an event
|
||||
|
@ -279,7 +335,7 @@ void event_remove(event_t *criterion)
|
|||
for (i=0; i<events.size(); i++)
|
||||
{
|
||||
event_t *n = events.at(i);
|
||||
if (event_match(criterion, n))
|
||||
if (event_match(criterion, *n))
|
||||
{
|
||||
killme.push_back(n);
|
||||
|
||||
|
@ -291,7 +347,7 @@ void event_remove(event_t *criterion)
|
|||
if (n->type == EVENT_SIGNAL)
|
||||
{
|
||||
event_t e = event_t::signal_event(n->param1.signal);
|
||||
if (event_get(&e, 0) == 1)
|
||||
if (event_get(e, 0) == 1)
|
||||
{
|
||||
signal_handle(e.param1.signal, 0);
|
||||
}
|
||||
|
@ -307,7 +363,7 @@ void event_remove(event_t *criterion)
|
|||
signal_unblock();
|
||||
}
|
||||
|
||||
int event_get(event_t *criterion, std::vector<event_t *> *out)
|
||||
int event_get(const event_t &criterion, std::vector<event_t *> *out)
|
||||
{
|
||||
size_t i;
|
||||
int found = 0;
|
||||
|
@ -315,12 +371,10 @@ int event_get(event_t *criterion, std::vector<event_t *> *out)
|
|||
if (events.empty())
|
||||
return 0;
|
||||
|
||||
CHECK(criterion, 0);
|
||||
|
||||
for (i=0; i<events.size(); i++)
|
||||
{
|
||||
event_t *n = events.at(i);
|
||||
if (event_match(criterion, n))
|
||||
if (event_match(criterion, *n))
|
||||
{
|
||||
found++;
|
||||
if (out)
|
||||
|
@ -364,9 +418,9 @@ static void event_free_kills()
|
|||
/**
|
||||
Test if the specified event is waiting to be killed
|
||||
*/
|
||||
static int event_is_killed(event_t *e)
|
||||
static int event_is_killed(const event_t &e)
|
||||
{
|
||||
return std::find(killme.begin(), killme.end(), e) != killme.end();
|
||||
return std::find(killme.begin(), killme.end(), &e) != killme.end();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -375,16 +429,18 @@ static int event_is_killed(event_t *e)
|
|||
optimize the 'no matches' path. This means that nothing is
|
||||
allocated/initialized unless needed.
|
||||
*/
|
||||
static void event_fire_internal(const event_t *event)
|
||||
static void event_fire_internal(const event_t &event)
|
||||
{
|
||||
|
||||
size_t i, j;
|
||||
event_list_t fire;
|
||||
|
||||
/*
|
||||
First we free all events that have been removed
|
||||
First we free all events that have been removed, but only if this
|
||||
invocation of event_fire_internal is not a recursive call.
|
||||
*/
|
||||
event_free_kills();
|
||||
if(is_event <= 1)
|
||||
event_free_kills();
|
||||
|
||||
if (events.empty())
|
||||
return;
|
||||
|
@ -403,7 +459,7 @@ static void event_fire_internal(const event_t *event)
|
|||
/*
|
||||
Check if this event is a match
|
||||
*/
|
||||
if (event_match(criterion, event))
|
||||
if (event_match(*criterion, event))
|
||||
{
|
||||
fire.push_back(criterion);
|
||||
}
|
||||
|
@ -427,7 +483,7 @@ static void event_fire_internal(const event_t *event)
|
|||
/*
|
||||
Check if this event has been removed, if so, dont fire it
|
||||
*/
|
||||
if (event_is_killed(criterion))
|
||||
if (event_is_killed(*criterion))
|
||||
continue;
|
||||
|
||||
/*
|
||||
|
@ -435,17 +491,17 @@ static void event_fire_internal(const event_t *event)
|
|||
*/
|
||||
wcstring buffer = criterion->function_name;
|
||||
|
||||
if (event->arguments.get())
|
||||
if (! event.arguments.empty())
|
||||
{
|
||||
for (j=0; j< event->arguments->size(); j++)
|
||||
for (j=0; j < event.arguments.size(); j++)
|
||||
{
|
||||
wcstring arg_esc = escape_string(event->arguments->at(j), 1);
|
||||
wcstring arg_esc = escape_string(event.arguments.at(j), 1);
|
||||
buffer += L" ";
|
||||
buffer += arg_esc;
|
||||
}
|
||||
}
|
||||
|
||||
// debug( 1, L"Event handler fires command '%ls'", buffer.c_str() );
|
||||
// debug( 1, L"Event handler fires command '%ls'", buffer.c_str() );
|
||||
|
||||
/*
|
||||
Event handlers are not part of the main flow of code, so
|
||||
|
@ -466,7 +522,8 @@ static void event_fire_internal(const event_t *event)
|
|||
/*
|
||||
Free killed events
|
||||
*/
|
||||
event_free_kills();
|
||||
if(is_event <= 1)
|
||||
event_free_kills();
|
||||
|
||||
}
|
||||
|
||||
|
@ -492,13 +549,13 @@ static void event_fire_delayed()
|
|||
for (i=0; i<blocked.size(); i++)
|
||||
{
|
||||
event_t *e = blocked.at(i);
|
||||
if (event_is_blocked(e))
|
||||
if (event_is_blocked(*e))
|
||||
{
|
||||
new_blocked.push_back(e);
|
||||
new_blocked.push_back(new event_t(*e));
|
||||
}
|
||||
else
|
||||
{
|
||||
event_fire_internal(e);
|
||||
event_fire_internal(*e);
|
||||
event_free(e);
|
||||
}
|
||||
}
|
||||
|
@ -520,7 +577,7 @@ static void event_fire_delayed()
|
|||
Set up
|
||||
*/
|
||||
event_t e = event_t::signal_event(0);
|
||||
e.arguments.reset(new wcstring_list_t(1)); //one element
|
||||
e.arguments.resize(1);
|
||||
lst = &sig_list[1-active_list];
|
||||
|
||||
if (lst->overflow)
|
||||
|
@ -534,19 +591,17 @@ static void event_fire_delayed()
|
|||
for (int i=0; i < lst->count; i++)
|
||||
{
|
||||
e.param1.signal = lst->signal[i];
|
||||
e.arguments->at(0) = sig2wcs(e.param1.signal);
|
||||
if (event_is_blocked(&e))
|
||||
e.arguments.at(0) = sig2wcs(e.param1.signal);
|
||||
if (event_is_blocked(e))
|
||||
{
|
||||
blocked.push_back(event_copy(&e, 1));
|
||||
blocked.push_back(new event_t(e));
|
||||
}
|
||||
else
|
||||
{
|
||||
event_fire_internal(&e);
|
||||
event_fire_internal(e);
|
||||
}
|
||||
}
|
||||
|
||||
e.arguments.reset(NULL);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,13 +638,13 @@ void event_fire(event_t *event)
|
|||
|
||||
if (event)
|
||||
{
|
||||
if (event_is_blocked(event))
|
||||
if (event_is_blocked(*event))
|
||||
{
|
||||
blocked.push_back(event_copy(event, 1));
|
||||
blocked.push_back(new event_t(*event));
|
||||
}
|
||||
else
|
||||
{
|
||||
event_fire_internal(event);
|
||||
event_fire_internal(*event);
|
||||
}
|
||||
}
|
||||
is_event--;
|
||||
|
@ -617,26 +672,15 @@ void event_free(event_t *e)
|
|||
delete e;
|
||||
}
|
||||
|
||||
|
||||
void event_fire_generic_internal(const wchar_t *name, ...)
|
||||
void event_fire_generic(const wchar_t *name, wcstring_list_t *args)
|
||||
{
|
||||
va_list va;
|
||||
wchar_t *arg;
|
||||
|
||||
CHECK(name,);
|
||||
|
||||
event_t ev(EVENT_GENERIC);
|
||||
ev.str_param1 = name;
|
||||
ev.arguments.reset(new wcstring_list_t);
|
||||
va_start(va, name);
|
||||
while ((arg=va_arg(va, wchar_t *))!= 0)
|
||||
{
|
||||
ev.arguments->push_back(arg);
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
if (args)
|
||||
ev.arguments = *args;
|
||||
event_fire(&ev);
|
||||
ev.arguments.reset(NULL);
|
||||
}
|
||||
|
||||
event_t event_t::signal_event(int sig)
|
||||
|
@ -659,14 +703,4 @@ event_t event_t::generic_event(const wcstring &str)
|
|||
event.str_param1 = str;
|
||||
return event;
|
||||
}
|
||||
|
||||
event_t::event_t(const event_t &x) :
|
||||
type(x.type),
|
||||
param1(x.param1),
|
||||
str_param1(x.str_param1),
|
||||
function_name(x.function_name)
|
||||
{
|
||||
const wcstring_list_t *ptr = x.arguments.get();
|
||||
if (ptr)
|
||||
arguments.reset(new wcstring_list_t(*ptr));
|
||||
}
|
||||
|
||||
|
|
19
event.h
19
event.h
|
@ -84,12 +84,13 @@ struct event_t
|
|||
event_fire. In all other situations, the value of this variable
|
||||
is ignored.
|
||||
*/
|
||||
std::auto_ptr<wcstring_list_t> arguments;
|
||||
wcstring_list_t arguments;
|
||||
|
||||
event_t(int t) : type(t), param1(), str_param1(), function_name(), arguments() { }
|
||||
|
||||
/** Copy constructor */
|
||||
event_t(const event_t &x);
|
||||
/** default copy constructor */
|
||||
//event_t(const event_t &x);
|
||||
|
||||
|
||||
static event_t signal_event(int sig);
|
||||
static event_t variable_event(const wcstring &str);
|
||||
|
@ -101,14 +102,14 @@ struct event_t
|
|||
|
||||
May not be called by a signal handler, since it may allocate new memory.
|
||||
*/
|
||||
void event_add_handler(const event_t *event);
|
||||
void event_add_handler(const event_t &event);
|
||||
|
||||
/**
|
||||
Remove all events matching the specified criterion.
|
||||
|
||||
May not be called by a signal handler, since it may free allocated memory.
|
||||
*/
|
||||
void event_remove(event_t *event);
|
||||
void event_remove(const event_t &event);
|
||||
|
||||
/**
|
||||
Return all events which match the specified event class
|
||||
|
@ -121,7 +122,7 @@ void event_remove(event_t *event);
|
|||
|
||||
\return the number of found matches
|
||||
*/
|
||||
int event_get(event_t *criterion, std::vector<event_t *> *out);
|
||||
int event_get(const event_t &criterion, std::vector<event_t *> *out);
|
||||
|
||||
/**
|
||||
Returns whether an event listener is registered for the given signal.
|
||||
|
@ -168,13 +169,11 @@ void event_free(event_t *e);
|
|||
/**
|
||||
Returns a string describing the specified event.
|
||||
*/
|
||||
wcstring event_get_desc(const event_t *e);
|
||||
wcstring event_get_desc(const event_t &e);
|
||||
|
||||
/**
|
||||
Fire a generic event with the specified name
|
||||
*/
|
||||
#define event_fire_generic( ... ) event_fire_generic_internal( __VA_ARGS__, NULL )
|
||||
|
||||
void event_fire_generic_internal(const wchar_t *name,...);
|
||||
void event_fire_generic(const wchar_t *name, wcstring_list_t *args = NULL);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -199,7 +199,7 @@ void function_add(const function_data_t &data, const parser_t &parser)
|
|||
/* Add event handlers */
|
||||
for (std::vector<event_t>::const_iterator iter = data.events.begin(); iter != data.events.end(); ++iter)
|
||||
{
|
||||
event_add_handler(&*iter);
|
||||
event_add_handler(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,7 +229,7 @@ static bool function_remove_ignore_autoload(const wcstring &name)
|
|||
{
|
||||
event_t ev(EVENT_ANY);
|
||||
ev.function_name=name;
|
||||
event_remove(&ev);
|
||||
event_remove(ev);
|
||||
}
|
||||
return erased;
|
||||
|
||||
|
|
|
@ -2077,6 +2077,7 @@ int parser_t::parse_job(process_t *p,
|
|||
|
||||
int tmp;
|
||||
const wchar_t *cmd = args.at(0).completion.c_str();
|
||||
wcstring_list_t event_args;
|
||||
|
||||
/*
|
||||
We couldn't find the specified command.
|
||||
|
@ -2157,7 +2158,9 @@ int parser_t::parse_job(process_t *p,
|
|||
current_tokenizer_pos=tmp;
|
||||
|
||||
job_set_flag(j, JOB_SKIP, 1);
|
||||
event_fire_generic(L"fish_command_not_found", (wchar_t *)(args.at(0).completion.c_str()));
|
||||
|
||||
event_args.push_back(args.at(0).completion);
|
||||
event_fire_generic(L"fish_command_not_found", &event_args);
|
||||
proc_set_last_status(err==ENOENT?STATUS_UNKNOWN_COMMAND:STATUS_NOT_EXECUTABLE);
|
||||
}
|
||||
}
|
||||
|
@ -3795,7 +3798,7 @@ if_block_t::if_block_t() :
|
|||
{
|
||||
}
|
||||
|
||||
event_block_t::event_block_t(const event_t *evt) :
|
||||
event_block_t::event_block_t(const event_t &evt) :
|
||||
block_t(EVENT),
|
||||
event(evt)
|
||||
{
|
||||
|
|
4
parser.h
4
parser.h
|
@ -158,8 +158,8 @@ struct if_block_t : public block_t
|
|||
|
||||
struct event_block_t : public block_t
|
||||
{
|
||||
const event_t * const event;
|
||||
event_block_t(const event_t *evt);
|
||||
event_t const &event;
|
||||
event_block_t(const event_t &evt);
|
||||
};
|
||||
|
||||
struct function_block_t : public block_t
|
||||
|
|
10
proc.cpp
10
proc.cpp
|
@ -162,7 +162,6 @@ static std::vector<int> interactive_stack;
|
|||
void proc_init()
|
||||
{
|
||||
proc_push_interactive(0);
|
||||
event.arguments.reset(new wcstring_list_t);
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,7 +193,6 @@ void job_free(job_t * j)
|
|||
|
||||
void proc_destroy()
|
||||
{
|
||||
event.arguments.reset(NULL);
|
||||
job_list_t &jobs = parser_t::principal_parser().job_list();
|
||||
while (! jobs.empty())
|
||||
{
|
||||
|
@ -603,11 +601,11 @@ void proc_fire_event(const wchar_t *msg, int type, pid_t pid, int status)
|
|||
event.type=type;
|
||||
event.param1.pid = pid;
|
||||
|
||||
event.arguments->push_back(msg);
|
||||
event.arguments->push_back(to_string<int>(pid));
|
||||
event.arguments->push_back(to_string<int>(status));
|
||||
event.arguments.push_back(msg);
|
||||
event.arguments.push_back(to_string<int>(pid));
|
||||
event.arguments.push_back(to_string<int>(status));
|
||||
event_fire(&event);
|
||||
event.arguments->resize(0);
|
||||
event.arguments.resize(0);
|
||||
}
|
||||
|
||||
int job_reap(bool interactive)
|
||||
|
|
1
tests/test9.err
Normal file
1
tests/test9.err
Normal file
|
@ -0,0 +1 @@
|
|||
emit: expected event name
|
28
tests/test9.in
Normal file
28
tests/test9.in
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Test events.
|
||||
|
||||
# This pattern caused a crash; github issue #449
|
||||
|
||||
set -g var before
|
||||
|
||||
function test1 --on-event test
|
||||
set -g var $var:test1
|
||||
functions -e test2
|
||||
end
|
||||
|
||||
function test2 --on-event test
|
||||
# this should not run, as test2 gets removed before it has a chance of running
|
||||
set -g var $var:test2a
|
||||
end
|
||||
emit test
|
||||
|
||||
echo $var
|
||||
|
||||
|
||||
function test3 --on-event test3
|
||||
echo received event test3 with args: $argv
|
||||
end
|
||||
|
||||
emit test3 foo bar
|
||||
|
||||
# test empty argument
|
||||
emit
|
2
tests/test9.out
Normal file
2
tests/test9.out
Normal file
|
@ -0,0 +1,2 @@
|
|||
before:test1
|
||||
received event test3 with args: foo bar
|
1
tests/test9.status
Normal file
1
tests/test9.status
Normal file
|
@ -0,0 +1 @@
|
|||
1
|
Loading…
Reference in New Issue
Block a user