aboutsummaryrefslogtreecommitdiffstats
path: root/src/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/filter.c')
-rw-r--r--src/filter.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/filter.c b/src/filter.c
new file mode 100644
index 00000000..581a7b72
--- /dev/null
+++ b/src/filter.c
@@ -0,0 +1,127 @@
+// Copyright 2019-2022 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "serd/filter.h"
+
+#include "serd/event.h"
+#include "serd/memory.h"
+#include "serd/statement.h"
+#include "serd/status.h"
+
+#include "memory.h"
+#include "sink.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+typedef struct {
+ const SerdSink* target;
+ SerdNode* subject;
+ SerdNode* predicate;
+ SerdNode* object;
+ SerdNode* graph;
+ bool inclusive;
+} SerdFilterData;
+
+static void
+free_data(void* const handle)
+{
+ if (handle) {
+ SerdFilterData* const data = (SerdFilterData*)handle;
+ SerdAllocator* const allocator = data->target->allocator;
+
+ serd_node_free(allocator, data->subject);
+ serd_node_free(allocator, data->predicate);
+ serd_node_free(allocator, data->object);
+ serd_node_free(allocator, data->graph);
+ serd_afree(allocator, data);
+ }
+}
+
+static SerdStatus
+serd_filter_on_event(void* const handle, const SerdEvent* const event)
+{
+ const SerdFilterData* const data = (SerdFilterData*)handle;
+
+ if (event->type == SERD_STATEMENT) {
+ const bool matches = serd_statement_matches(event->statement.statement,
+ data->subject,
+ data->predicate,
+ data->object,
+ data->graph);
+
+ if (data->inclusive == matches) {
+ // Emit statement with reset flags to avoid confusing the writer
+ SerdEvent out_event = *event;
+ out_event.statement.flags = 0U;
+ return serd_sink_write_event(data->target, &out_event);
+ }
+
+ return SERD_SUCCESS; // Skip statement
+ }
+
+ return event->type == SERD_END ? SERD_SUCCESS
+ : serd_sink_write_event(data->target, event);
+}
+
+SerdSink*
+serd_filter_new(const SerdWorld* const world,
+ const SerdSink* const target,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const graph,
+ const bool inclusive)
+{
+ assert(world);
+ assert(target);
+
+ SerdAllocator* const allocator = serd_world_allocator(world);
+ SerdFilterData* const data =
+ (SerdFilterData*)serd_wcalloc(world, 1, sizeof(SerdFilterData));
+
+ if (!data) {
+ return NULL;
+ }
+
+ data->target = target;
+ data->inclusive = inclusive;
+
+ if (subject && serd_node_type(subject) != SERD_VARIABLE) {
+ if (!(data->subject = serd_node_copy(allocator, subject))) {
+ free_data(data);
+ return NULL;
+ }
+ }
+
+ if (predicate && serd_node_type(predicate) != SERD_VARIABLE) {
+ if (!(data->predicate = serd_node_copy(allocator, predicate))) {
+ free_data(data);
+ return NULL;
+ }
+ }
+
+ if (object && serd_node_type(object) != SERD_VARIABLE) {
+ if (!(data->object = serd_node_copy(allocator, object))) {
+ free_data(data);
+ return NULL;
+ }
+ }
+
+ if (graph && serd_node_type(graph) != SERD_VARIABLE) {
+ if (!(data->graph = serd_node_copy(allocator, graph))) {
+ free_data(data);
+ return NULL;
+ }
+ }
+
+ SerdSink* const sink =
+ serd_sink_new(allocator, data, serd_filter_on_event, free_data);
+
+ if (!sink) {
+ free_data(data);
+ }
+
+ return sink;
+}