Compare commits

...

3 Commits

Author SHA1 Message Date
Vftdan 011772a24a Loading event predicates from config 2024-08-16 22:48:09 +02:00
Vftdan 23a0fa002f Compiling event_predicate 2024-08-16 22:46:11 +02:00
Vftdan 39ea42018f Fix event_predicate
- Leaking handle lists when deleting aggregate predicates
 - Wrong dynamic array growth condition
 - Handle invalid predicate type field
2024-08-16 22:43:37 +02:00
7 changed files with 183 additions and 5 deletions

View File

@ -12,7 +12,7 @@ CPPFLAGS += $(shell pkg-config --cflags $(DEPS))
LDLIBS += $(shell pkg-config --libs $(DEPS))
INTERP ?=
MAIN = main
OBJS = main.o events.o processing.o graph.o config.o event_code_names.o hash_table.o module_registry.o nodes/getchar.o nodes/print.o nodes/evdev.o nodes/tee.o
OBJS = main.o events.o processing.o graph.o config.o event_code_names.o hash_table.o module_registry.o event_predicate.o nodes/getchar.o nodes/print.o nodes/evdev.o nodes/tee.o
all: $(MAIN)

144
config.c
View File

@ -245,6 +245,126 @@ load_enums_section(const config_setting_t *config_section, ConstantRegistry *con
}
}
static EventPredicateType
parse_event_predicate_type(const char *name)
{
if (!name) {
return EVPRED_INVALID;
}
if (strcmp(name, "accept") == 0) {
return EVPRED_ACCEPT;
}
if (strcmp(name, "code_ns") == 0) {
return EVPRED_CODE_NS;
}
if (strcmp(name, "code_major") == 0) {
return EVPRED_CODE_MAJOR;
}
if (strcmp(name, "code_minor") == 0) {
return EVPRED_CODE_MINOR;
}
if (strcmp(name, "payload") == 0) {
return EVPRED_PAYLOAD;
}
if (strcmp(name, "conjunction") == 0 || strcmp(name, "and") == 0) {
return EVPRED_CONJUNCTION;
}
if (strcmp(name, "disjunction") == 0 || strcmp(name, "or") == 0) {
return EVPRED_DISJUNCTION;
}
return EVPRED_INVALID;
}
static EventPredicateHandle
load_single_predicate(const config_setting_t * setting, EventPredicateHandleRegistry * registry, const ConstantRegistry * constants)
{
const char *name = NULL;
const char *type_name = NULL;
config_setting_lookup_string(setting, "name", &name);
config_setting_lookup_string(setting, "type", &type_name);
if (!type_name) {
return -1;
}
EventPredicate predicate;
EventPredicateType type = parse_event_predicate_type(type_name);
predicate.type = type;
switch (type) {
case EVPRED_INVALID:
return -1;
case EVPRED_ACCEPT:
break;
case EVPRED_CODE_NS...EVPRED_PAYLOAD:
{
int64_t min_value = INT64_MIN;
int64_t max_value = INT64_MAX;
min_value = resolve_constant_or(constants, config_setting_get_member(setting, "min"), min_value);
max_value = resolve_constant_or(constants, config_setting_get_member(setting, "max"), max_value);
predicate.range_data.min_value = min_value;
predicate.range_data.max_value = max_value;
}
break;
case EVPRED_CONJUNCTION:
case EVPRED_DISJUNCTION:
{
config_setting_t *args = config_setting_get_member(setting, "args");
EventPredicateHandle *handles = NULL;
ssize_t length = config_setting_length(args);
if (length > 0) {
handles = T_ALLOC(length, EventPredicateHandle);
for (ssize_t i = 0; i < length; ++i) {
handles[i] = resolve_event_predicate(registry, constants, config_setting_get_elem(args, i));
}
}
predicate.aggregate_data.length = length;
predicate.aggregate_data.handles = handles;
}
break;
default:
return -1;
}
long long enabled = resolve_constant_or(constants, config_setting_get_member(setting, "enabled"), true);
long long inverted = resolve_constant_or(constants, config_setting_get_member(setting, "inverted"), false);
predicate.enabled = enabled != 0;
predicate.inverted = inverted != 0;
EventPredicateHandle handle = event_predicate_register(predicate);
if (handle < 0) {
if ((predicate.type == EVPRED_CONJUNCTION || predicate.type == EVPRED_DISJUNCTION) && predicate.aggregate_data.handles) {
free(predicate.aggregate_data.handles);
predicate.aggregate_data.handles = NULL;
predicate.aggregate_data.length = 0;
}
}
return handle;
}
static void
load_predicates_section(const config_setting_t *config_section, EventPredicateHandleRegistry *predicates, const ConstantRegistry *constants)
{
if (!config_section) {
return;
}
ssize_t length = config_setting_length(config_section);
if (length <= 0) {
return;
}
for (ssize_t i = 0; i < length; ++i) {
config_setting_t *predicate_def = config_setting_get_elem(config_section, i);
if (!predicate_def) {
continue;
}
const char *name = config_setting_name(predicate_def);
EventPredicateHandle handle = resolve_event_predicate(predicates, constants, predicate_def);
if (handle >= 0 && name != NULL) {
hash_table_insert(predicates, hash_table_key_from_cstr(name), &handle);
}
}
}
bool
load_config(const config_setting_t *config_root, FullConfig *config)
{
@ -255,10 +375,13 @@ load_config(const config_setting_t *config_root, FullConfig *config)
const config_setting_t *channel_config = config_setting_get_member(config_root, "channels");
const config_setting_t *constants_config = config_setting_get_member(config_root, "constants");
const config_setting_t *enums_config = config_setting_get_member(config_root, "enums");
const config_setting_t *predicates_config = config_setting_get_member(config_root, "predicates");
hash_table_init(&config->constants, NULL);
populate_event_codes(&config->constants);
load_constants_section(constants_config, &config->constants);
load_enums_section(enums_config, &config->constants);
hash_table_init(&config->predicates, NULL);
load_predicates_section(predicates_config, &config->predicates, &config->constants);
config->nodes = load_nodes_section(node_config);
config->channels = load_channels_section(channel_config, &config->constants);
return true;
@ -281,6 +404,7 @@ reset_config(FullConfig *config)
config->channels.length = 0;
}
hash_table_deinit(&config->constants);
hash_table_deinit(&config->predicates);
}
long long
@ -305,3 +429,23 @@ resolve_constant_or(const ConstantRegistry * registry, const config_setting_t *
}
return dflt;
}
EventPredicateHandle
resolve_event_predicate(EventPredicateHandleRegistry * registry, const ConstantRegistry * constants, const config_setting_t * setting)
{
if (!setting) {
return -1;
}
if (config_setting_type(setting) == CONFIG_TYPE_STRING) {
if (!registry) {
return -1;
}
const char *name = config_setting_get_string(setting);
HashTableIndex idx = hash_table_find(registry, hash_table_key_from_cstr(name));
if (idx < 0) {
return -1;
}
return registry->value_array[idx];
}
return load_single_predicate(setting, registry, constants);
}

View File

@ -2,6 +2,25 @@ enums = {
namespaces: ["stdin", "clickpad"];
};
predicates = {
is_evdev = {
type = "code_ns";
min = "namespaces.clickpad";
max = "namespaces.clickpad";
};
key_event = {
type = "and";
args = (
"is_evdev",
{
type = "code_major";
min = "event_type.KEY";
max = "event_type.KEY";
}
);
}
};
nodes = {
stdin = {
type = "getchar";

View File

@ -4,6 +4,7 @@
#include <libconfig.h>
#include "defs.h"
#include "hash_table.h"
#include "event_predicate.h"
typedef struct {
const char *name;
@ -29,16 +30,19 @@ typedef struct {
} GraphChannelConfigSection;
typedef TYPED_HASH_TABLE(long long) ConstantRegistry;
typedef TYPED_HASH_TABLE(EventPredicateHandle) EventPredicateHandleRegistry;
typedef struct {
GraphNodeConfigSection nodes;
GraphChannelConfigSection channels;
ConstantRegistry constants;
EventPredicateHandleRegistry predicates;
} FullConfig;
bool load_config(const config_setting_t *config_root, FullConfig *config);
void reset_config(FullConfig *config);
long long resolve_constant_or(const ConstantRegistry * registry, const config_setting_t * setting, long long dflt);
EventPredicateHandle resolve_event_predicate(EventPredicateHandleRegistry * registry, const ConstantRegistry * constants, const config_setting_t * setting);
__attribute__((unused)) inline static long long
resolve_constant(const ConstantRegistry * registry, const config_setting_t * setting)

View File

@ -38,6 +38,14 @@ static void
event_predicate_list_clear(EventPredicateList * lst)
{
if (lst->values) {
for (size_t i = 0; i < lst->length; ++i) {
EventPredicateType type = lst->values[i].type;
if (type == EVPRED_CONJUNCTION || type == EVPRED_DISJUNCTION) {
if (lst->values[i].aggregate_data.handles) {
free(lst->values[i].aggregate_data.handles);
}
}
}
free(lst->values);
lst->values = NULL;
}
@ -46,16 +54,16 @@ event_predicate_list_clear(EventPredicateList * lst)
}
EventPredicateHandle
event_predicate_register(EventPredicate filter)
event_predicate_register(EventPredicate predicate)
{
size_t i = predicates.length;
if (i >= INT32_MAX) {
return -1;
}
while (i <= predicates.capacity) {
while (i >= predicates.capacity) {
event_predicate_list_extend(&predicates);
}
predicates.values[i] = filter;
predicates.values[i] = predicate;
predicates.length = i + 1;
return (EventPredicateHandle) i;
}
@ -157,6 +165,8 @@ event_predicate_apply(EventPredicateHandle handle, EventNode * event)
}
}
break;
default:
return EVPREDRES_DISABLED;
}
if (ptr->inverted) {
accepted = !accepted;

View File

@ -41,7 +41,7 @@ struct event_predicate {
};
};
EventPredicateHandle event_predicate_register(EventPredicate filter);
EventPredicateHandle event_predicate_register(EventPredicate predicate);
EventPredicate event_predicate_get(EventPredicateHandle handle);
EventPredicateResult event_predicate_apply(EventPredicateHandle handle, EventNode * event);
void event_predicate_set_enabled(EventPredicateHandle handle, bool enabled);

1
main.c
View File

@ -87,6 +87,7 @@ main(int argc, char ** argv)
free(nodes);
reset_config(&loaded_config);
event_predicate_reset();
config_destroy(&config_tree);
io_subscription_list_deinit(&state.wait_output);