mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-31 20:31:19 -03:00
Merge branch 'event-bug-test' of git://github.com/JanKanis/fish-shell into JanKanis-event-bug-test
This commit is contained in:
14
builtin.cpp
14
builtin.cpp
@@ -1009,15 +1009,15 @@ static int builtin_emit(parser_t &parser, wchar_t **argv)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; woptind < argc; woptind++)
|
if(!argv[woptind]) {
|
||||||
{
|
append_format(stderr_buffer, L"%ls: expected event name\n", argv[0]);
|
||||||
event_fire_generic(argv[woptind]);
|
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;
|
return STATUS_BUILTIN_OK;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1099,7 +1099,7 @@ static void functions_def(const wcstring &name, wcstring &out)
|
|||||||
search.function_name = name;
|
search.function_name = name;
|
||||||
|
|
||||||
std::vector<event_t *> ev;
|
std::vector<event_t *> ev;
|
||||||
event_get(&search, &ev);
|
event_get(search, &ev);
|
||||||
|
|
||||||
out.append(L"function ");
|
out.append(L"function ");
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
\section emit emit - Emit a generic event
|
\section emit emit - Emit a generic event
|
||||||
|
|
||||||
\subsection block-synopsis Synopsis
|
\subsection block-synopsis Synopsis
|
||||||
<tt>emit EVENT_NAME</tt>
|
<tt>emit EVENT_NAME [ARGUMENTS...]</tt>
|
||||||
|
|
||||||
\subsection emit-description Description
|
\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
|
\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.
|
event named 'test_event', and then emits an event of that type.
|
||||||
|
|
||||||
<pre>function event_test --on-event test_event
|
<pre>function event_test --on-event test_event
|
||||||
echo event test!!!
|
echo event test: $argv
|
||||||
end
|
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();
|
mark_changed_exported();
|
||||||
|
|
||||||
event_t ev = event_t::variable_event(name);
|
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(L"VARIABLE");
|
ev.arguments.push_back(str);
|
||||||
ev.arguments->push_back(str);
|
ev.arguments.push_back(name);
|
||||||
ev.arguments->push_back(name);
|
|
||||||
event_fire(&ev);
|
event_fire(&ev);
|
||||||
ev.arguments.reset(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name)
|
if (name)
|
||||||
@@ -961,15 +959,13 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode)
|
|||||||
if (!is_universal)
|
if (!is_universal)
|
||||||
{
|
{
|
||||||
event_t ev = event_t::variable_event(key);
|
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"VARIABLE");
|
ev.arguments.push_back(L"SET");
|
||||||
ev.arguments->push_back(L"SET");
|
ev.arguments.push_back(key);
|
||||||
ev.arguments->push_back(key);
|
|
||||||
|
|
||||||
// debug( 1, L"env_set: fire events on variable %ls", key );
|
// debug( 1, L"env_set: fire events on variable %ls", key );
|
||||||
event_fire(&ev);
|
event_fire(&ev);
|
||||||
// debug( 1, L"env_set: return from event firing" );
|
// debug( 1, L"env_set: return from event firing" );
|
||||||
ev.arguments.reset(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
react_to_variable_change(key);
|
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))
|
if (try_remove(first_node, key.c_str(), var_mode))
|
||||||
{
|
{
|
||||||
event_t ev = event_t::variable_event(key);
|
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"VARIABLE");
|
ev.arguments.push_back(L"ERASE");
|
||||||
ev.arguments->push_back(L"ERASE");
|
ev.arguments.push_back(key);
|
||||||
ev.arguments->push_back(key);
|
|
||||||
|
|
||||||
event_fire(&ev);
|
event_fire(&ev);
|
||||||
|
|
||||||
ev.arguments.reset(NULL);
|
|
||||||
erased = 1;
|
erased = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
250
event.cpp
250
event.cpp
@@ -25,6 +25,7 @@
|
|||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Number of signals that can be queued before an overflow occurs
|
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.
|
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 the function names are both non-empty and different, then it's not a match */
|
||||||
if (! classv->function_name.empty() &&
|
if (! classv.function_name.empty() &&
|
||||||
! instance->function_name.empty() &&
|
! instance.function_name.empty() &&
|
||||||
classv->function_name != instance->function_name)
|
classv.function_name != instance.function_name)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classv->type == EVENT_ANY)
|
if (classv.type == EVENT_ANY)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (classv->type != instance->type)
|
if (classv.type != instance.type)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
switch (classv->type)
|
switch (classv.type)
|
||||||
{
|
{
|
||||||
|
|
||||||
case EVENT_SIGNAL:
|
case EVENT_SIGNAL:
|
||||||
if (classv->param1.signal == EVENT_ANY_SIGNAL)
|
if (classv.param1.signal == EVENT_ANY_SIGNAL)
|
||||||
return 1;
|
return 1;
|
||||||
return classv->param1.signal == instance->param1.signal;
|
return classv.param1.signal == instance.param1.signal;
|
||||||
|
|
||||||
case EVENT_VARIABLE:
|
case EVENT_VARIABLE:
|
||||||
return instance->str_param1 == classv->str_param1;
|
return instance.str_param1 == classv.str_param1;
|
||||||
|
|
||||||
case EVENT_EXIT:
|
case EVENT_EXIT:
|
||||||
if (classv->param1.pid == EVENT_ANY_PID)
|
if (classv.param1.pid == EVENT_ANY_PID)
|
||||||
return 1;
|
return 1;
|
||||||
return classv->param1.pid == instance->param1.pid;
|
return classv.param1.pid == instance.param1.pid;
|
||||||
|
|
||||||
case EVENT_JOB_ID:
|
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:
|
case EVENT_GENERIC:
|
||||||
return instance->str_param1 == classv->str_param1;
|
return instance.str_param1 == classv.str_param1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This should never be reached
|
This should never be reached
|
||||||
*/
|
*/
|
||||||
|
debug(0, "Warning: Unreachable code reached in event_match in event.cpp\n");
|
||||||
return 0;
|
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
|
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;
|
block_t *block;
|
||||||
parser_t &parser = parser_t::principal_parser();
|
parser_t &parser = parser_t::principal_parser();
|
||||||
for (block = parser.current_block; block; block = block->outer)
|
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 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;
|
wcstring result;
|
||||||
switch (e->type)
|
switch (e.type)
|
||||||
{
|
{
|
||||||
|
|
||||||
case EVENT_SIGNAL:
|
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;
|
break;
|
||||||
|
|
||||||
case EVENT_VARIABLE:
|
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;
|
break;
|
||||||
|
|
||||||
case EVENT_EXIT:
|
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
|
else
|
||||||
{
|
{
|
||||||
job_t *j = job_get_from_pid(-e->param1.pid);
|
job_t *j = job_get_from_pid(-e.param1.pid);
|
||||||
if (j)
|
if (j)
|
||||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr());
|
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr());
|
||||||
else
|
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;
|
break;
|
||||||
|
|
||||||
case EVENT_JOB_ID:
|
case EVENT_JOB_ID:
|
||||||
{
|
{
|
||||||
job_t *j = job_get(e->param1.job_id);
|
job_t *j = job_get(e.param1.job_id);
|
||||||
if (j)
|
if (j)
|
||||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr());
|
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr());
|
||||||
else
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EVENT_GENERIC:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result = format_string(_(L"Unknown event type"));
|
result = format_string(_(L"Unknown event type '0x%x'"), e.type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -237,13 +221,82 @@ static void show_all_handlers(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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;
|
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)
|
if (e->type == EVENT_SIGNAL)
|
||||||
{
|
{
|
||||||
@@ -256,13 +309,16 @@ void event_add_handler(const event_t *event)
|
|||||||
signal_unblock();
|
signal_unblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void event_remove(event_t *criterion)
|
void event_remove(const event_t &criterion)
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
event_list_t new_list;
|
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
|
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++)
|
for (i=0; i<events.size(); i++)
|
||||||
{
|
{
|
||||||
event_t *n = events.at(i);
|
event_t *n = events.at(i);
|
||||||
if (event_match(criterion, n))
|
if (event_match(criterion, *n))
|
||||||
{
|
{
|
||||||
killme.push_back(n);
|
killme.push_back(n);
|
||||||
|
|
||||||
@@ -291,7 +347,7 @@ void event_remove(event_t *criterion)
|
|||||||
if (n->type == EVENT_SIGNAL)
|
if (n->type == EVENT_SIGNAL)
|
||||||
{
|
{
|
||||||
event_t e = event_t::signal_event(n->param1.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);
|
signal_handle(e.param1.signal, 0);
|
||||||
}
|
}
|
||||||
@@ -307,7 +363,7 @@ void event_remove(event_t *criterion)
|
|||||||
signal_unblock();
|
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;
|
size_t i;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
@@ -315,12 +371,10 @@ int event_get(event_t *criterion, std::vector<event_t *> *out)
|
|||||||
if (events.empty())
|
if (events.empty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
CHECK(criterion, 0);
|
|
||||||
|
|
||||||
for (i=0; i<events.size(); i++)
|
for (i=0; i<events.size(); i++)
|
||||||
{
|
{
|
||||||
event_t *n = events.at(i);
|
event_t *n = events.at(i);
|
||||||
if (event_match(criterion, n))
|
if (event_match(criterion, *n))
|
||||||
{
|
{
|
||||||
found++;
|
found++;
|
||||||
if (out)
|
if (out)
|
||||||
@@ -364,9 +418,9 @@ static void event_free_kills()
|
|||||||
/**
|
/**
|
||||||
Test if the specified event is waiting to be killed
|
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
|
optimize the 'no matches' path. This means that nothing is
|
||||||
allocated/initialized unless needed.
|
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;
|
size_t i, j;
|
||||||
event_list_t fire;
|
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())
|
if (events.empty())
|
||||||
return;
|
return;
|
||||||
@@ -403,7 +459,7 @@ static void event_fire_internal(const event_t *event)
|
|||||||
/*
|
/*
|
||||||
Check if this event is a match
|
Check if this event is a match
|
||||||
*/
|
*/
|
||||||
if (event_match(criterion, event))
|
if (event_match(*criterion, event))
|
||||||
{
|
{
|
||||||
fire.push_back(criterion);
|
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
|
Check if this event has been removed, if so, dont fire it
|
||||||
*/
|
*/
|
||||||
if (event_is_killed(criterion))
|
if (event_is_killed(*criterion))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -435,17 +491,17 @@ static void event_fire_internal(const event_t *event)
|
|||||||
*/
|
*/
|
||||||
wcstring buffer = criterion->function_name;
|
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 += L" ";
|
||||||
buffer += arg_esc;
|
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
|
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
|
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++)
|
for (i=0; i<blocked.size(); i++)
|
||||||
{
|
{
|
||||||
event_t *e = blocked.at(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
|
else
|
||||||
{
|
{
|
||||||
event_fire_internal(e);
|
event_fire_internal(*e);
|
||||||
event_free(e);
|
event_free(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,7 +577,7 @@ static void event_fire_delayed()
|
|||||||
Set up
|
Set up
|
||||||
*/
|
*/
|
||||||
event_t e = event_t::signal_event(0);
|
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];
|
lst = &sig_list[1-active_list];
|
||||||
|
|
||||||
if (lst->overflow)
|
if (lst->overflow)
|
||||||
@@ -534,19 +591,17 @@ static void event_fire_delayed()
|
|||||||
for (int i=0; i < lst->count; i++)
|
for (int i=0; i < lst->count; i++)
|
||||||
{
|
{
|
||||||
e.param1.signal = lst->signal[i];
|
e.param1.signal = lst->signal[i];
|
||||||
e.arguments->at(0) = sig2wcs(e.param1.signal);
|
e.arguments.at(0) = sig2wcs(e.param1.signal);
|
||||||
if (event_is_blocked(&e))
|
if (event_is_blocked(e))
|
||||||
{
|
{
|
||||||
blocked.push_back(event_copy(&e, 1));
|
blocked.push_back(new event_t(e));
|
||||||
}
|
}
|
||||||
else
|
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)
|
||||||
{
|
{
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
event_fire_internal(event);
|
event_fire_internal(*event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is_event--;
|
is_event--;
|
||||||
@@ -617,26 +672,15 @@ void event_free(event_t *e)
|
|||||||
delete e;
|
delete e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void event_fire_generic(const wchar_t *name, wcstring_list_t *args)
|
||||||
void event_fire_generic_internal(const wchar_t *name, ...)
|
|
||||||
{
|
{
|
||||||
va_list va;
|
|
||||||
wchar_t *arg;
|
|
||||||
|
|
||||||
CHECK(name,);
|
CHECK(name,);
|
||||||
|
|
||||||
event_t ev(EVENT_GENERIC);
|
event_t ev(EVENT_GENERIC);
|
||||||
ev.str_param1 = name;
|
ev.str_param1 = name;
|
||||||
ev.arguments.reset(new wcstring_list_t);
|
if (args)
|
||||||
va_start(va, name);
|
ev.arguments = *args;
|
||||||
while ((arg=va_arg(va, wchar_t *))!= 0)
|
|
||||||
{
|
|
||||||
ev.arguments->push_back(arg);
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
event_fire(&ev);
|
event_fire(&ev);
|
||||||
ev.arguments.reset(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event_t event_t::signal_event(int sig)
|
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;
|
event.str_param1 = str;
|
||||||
return event;
|
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
|
event_fire. In all other situations, the value of this variable
|
||||||
is ignored.
|
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() { }
|
event_t(int t) : type(t), param1(), str_param1(), function_name(), arguments() { }
|
||||||
|
|
||||||
/** Copy constructor */
|
/** default copy constructor */
|
||||||
event_t(const event_t &x);
|
//event_t(const event_t &x);
|
||||||
|
|
||||||
|
|
||||||
static event_t signal_event(int sig);
|
static event_t signal_event(int sig);
|
||||||
static event_t variable_event(const wcstring &str);
|
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.
|
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.
|
Remove all events matching the specified criterion.
|
||||||
|
|
||||||
May not be called by a signal handler, since it may free allocated memory.
|
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
|
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
|
\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.
|
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.
|
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
|
Fire a generic event with the specified name
|
||||||
*/
|
*/
|
||||||
#define event_fire_generic( ... ) event_fire_generic_internal( __VA_ARGS__, NULL )
|
void event_fire_generic(const wchar_t *name, wcstring_list_t *args = NULL);
|
||||||
|
|
||||||
void event_fire_generic_internal(const wchar_t *name,...);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ void function_add(const function_data_t &data, const parser_t &parser)
|
|||||||
/* Add event handlers */
|
/* Add event handlers */
|
||||||
for (std::vector<event_t>::const_iterator iter = data.events.begin(); iter != data.events.end(); ++iter)
|
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);
|
event_t ev(EVENT_ANY);
|
||||||
ev.function_name=name;
|
ev.function_name=name;
|
||||||
event_remove(&ev);
|
event_remove(ev);
|
||||||
}
|
}
|
||||||
return erased;
|
return erased;
|
||||||
|
|
||||||
|
|||||||
@@ -2077,6 +2077,7 @@ int parser_t::parse_job(process_t *p,
|
|||||||
|
|
||||||
int tmp;
|
int tmp;
|
||||||
const wchar_t *cmd = args.at(0).completion.c_str();
|
const wchar_t *cmd = args.at(0).completion.c_str();
|
||||||
|
wcstring_list_t event_args;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We couldn't find the specified command.
|
We couldn't find the specified command.
|
||||||
@@ -2157,7 +2158,9 @@ int parser_t::parse_job(process_t *p,
|
|||||||
current_tokenizer_pos=tmp;
|
current_tokenizer_pos=tmp;
|
||||||
|
|
||||||
job_set_flag(j, JOB_SKIP, 1);
|
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);
|
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),
|
block_t(EVENT),
|
||||||
event(evt)
|
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
|
struct event_block_t : public block_t
|
||||||
{
|
{
|
||||||
const event_t * const event;
|
event_t const &event;
|
||||||
event_block_t(const event_t *evt);
|
event_block_t(const event_t &evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct function_block_t : public block_t
|
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()
|
void proc_init()
|
||||||
{
|
{
|
||||||
proc_push_interactive(0);
|
proc_push_interactive(0);
|
||||||
event.arguments.reset(new wcstring_list_t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -194,7 +193,6 @@ void job_free(job_t * j)
|
|||||||
|
|
||||||
void proc_destroy()
|
void proc_destroy()
|
||||||
{
|
{
|
||||||
event.arguments.reset(NULL);
|
|
||||||
job_list_t &jobs = parser_t::principal_parser().job_list();
|
job_list_t &jobs = parser_t::principal_parser().job_list();
|
||||||
while (! jobs.empty())
|
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.type=type;
|
||||||
event.param1.pid = pid;
|
event.param1.pid = pid;
|
||||||
|
|
||||||
event.arguments->push_back(msg);
|
event.arguments.push_back(msg);
|
||||||
event.arguments->push_back(to_string<int>(pid));
|
event.arguments.push_back(to_string<int>(pid));
|
||||||
event.arguments->push_back(to_string<int>(status));
|
event.arguments.push_back(to_string<int>(status));
|
||||||
event_fire(&event);
|
event_fire(&event);
|
||||||
event.arguments->resize(0);
|
event.arguments.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int job_reap(bool interactive)
|
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
|
||||||
Reference in New Issue
Block a user