aboutsummaryrefslogtreecommitdiffstats
path: root/src/node_syntax.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/node_syntax.c')
-rw-r--r--src/node_syntax.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/node_syntax.c b/src/node_syntax.c
new file mode 100644
index 00000000..b40bc0dc
--- /dev/null
+++ b/src/node_syntax.c
@@ -0,0 +1,189 @@
+// Copyright 2011-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "memory.h"
+#include "writer.h"
+
+#include "serd/buffer.h"
+#include "serd/env.h"
+#include "serd/event.h"
+#include "serd/input_stream.h"
+#include "serd/memory.h"
+#include "serd/node.h"
+#include "serd/node_syntax.h"
+#include "serd/output_stream.h"
+#include "serd/reader.h"
+#include "serd/sink.h"
+#include "serd/statement.h"
+#include "serd/status.h"
+#include "serd/string_view.h"
+#include "serd/syntax.h"
+#include "serd/world.h"
+#include "serd/writer.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct {
+ SerdAllocator* allocator;
+ SerdNode* object;
+} NodeSyntaxContext;
+
+static SerdStatus
+on_syntax_event(void* const handle, const SerdEvent* const event)
+{
+ NodeSyntaxContext* const ctx = (NodeSyntaxContext*)handle;
+
+ if (event->type == SERD_STATEMENT) {
+ ctx->object = serd_node_copy(
+ ctx->allocator, serd_statement_object(event->statement.statement));
+ }
+
+ return SERD_SUCCESS;
+}
+
+static SerdNode*
+serd_node_from_syntax_in(SerdWorld* const world,
+ const char* const str,
+ const SerdSyntax syntax,
+ SerdEnv* const env)
+{
+ assert(str);
+
+ static const char* const prelude =
+ "_:s <http://www.w3.org/2000/01/rdf-schema#object>";
+
+ SerdAllocator* const alloc = serd_world_allocator(world);
+
+ const size_t str_len = strlen(str);
+ const size_t doc_len = strlen(prelude) + str_len + 5;
+ NodeSyntaxContext ctx = {serd_world_allocator(world), NULL};
+ char* const doc = (char*)serd_wcalloc(world, doc_len + 2, 1);
+ SerdSink* const sink = serd_sink_new(alloc, &ctx, on_syntax_event, NULL);
+
+ if (doc && sink) {
+ snprintf(doc, doc_len + 1, "%s %s .", prelude, str);
+
+ const SerdLimits old_limits = serd_world_limits(world);
+ const SerdLimits limits = {1024 + doc_len, 8U};
+ serd_world_set_limits(world, limits);
+
+ SerdReader* const reader = serd_reader_new(
+ world,
+ syntax,
+ SERD_READ_RELATIVE | SERD_READ_GLOBAL | SERD_READ_GENERATED,
+ env,
+ sink);
+
+ if (reader) {
+ const char* position = doc;
+ SerdInputStream in = serd_open_input_string(&position);
+ serd_reader_start(reader, &in, NULL, 1);
+ serd_reader_read_document(reader);
+ serd_reader_finish(reader);
+ serd_close_input(&in);
+ }
+
+ serd_reader_free(reader);
+ serd_world_set_limits(world, old_limits);
+ }
+
+ serd_sink_free(sink);
+ serd_wfree(world, doc);
+
+ return ctx.object;
+}
+
+SerdNode*
+serd_node_from_syntax(SerdAllocator* const allocator,
+ const char* const str,
+ const SerdSyntax syntax,
+ SerdEnv* const env)
+{
+ assert(str);
+
+ SerdWorld* const temp_world = serd_world_new(allocator);
+ if (!temp_world) {
+ return NULL;
+ }
+
+ SerdNode* node = NULL;
+ if (env) {
+ node = serd_node_from_syntax_in(temp_world, str, syntax, env);
+ } else {
+ SerdEnv* const temp_env = serd_env_new(allocator, serd_empty_string());
+ if (temp_env) {
+ node = serd_node_from_syntax_in(temp_world, str, syntax, temp_env);
+ }
+ serd_env_free(temp_env);
+ }
+
+ serd_world_free(temp_world);
+ return node;
+}
+
+static char*
+serd_node_to_syntax_in(SerdWorld* const world,
+ const SerdNode* const node,
+ const SerdSyntax syntax,
+ const SerdEnv* const env)
+{
+ SerdBuffer buffer = {serd_world_allocator(world), NULL, 0};
+ SerdOutputStream out = serd_open_output_buffer(&buffer);
+
+ const SerdLimits old_limits = serd_world_limits(world);
+ const SerdLimits limits = {0U, 4U};
+ serd_world_set_limits(world, limits);
+
+ SerdWriter* const writer = serd_writer_new(world, syntax, 0, env, &out, 1);
+ serd_world_set_limits(world, old_limits);
+ if (!writer) {
+ return NULL;
+ }
+
+ char* result = NULL;
+ if (!serd_writer_write_node(writer, node) && !serd_writer_finish(writer)) {
+ if (!serd_close_output(&out)) {
+ result = (char*)buffer.buf;
+ }
+ } else {
+ serd_close_output(&out);
+ }
+
+ serd_writer_free(writer);
+
+ if (!result) {
+ serd_wfree(world, buffer.buf);
+ }
+
+ return result;
+}
+
+char*
+serd_node_to_syntax(SerdAllocator* const allocator,
+ const SerdNode* const node,
+ const SerdSyntax syntax,
+ const SerdEnv* const env)
+{
+ assert(node);
+
+ SerdWorld* const temp_world = serd_world_new(allocator);
+ if (!temp_world) {
+ return NULL;
+ }
+
+ char* string = NULL;
+ if (env) {
+ string = serd_node_to_syntax_in(temp_world, node, syntax, env);
+ } else {
+ SerdEnv* const temp_env = serd_env_new(allocator, serd_empty_string());
+ if (temp_env) {
+ string = serd_node_to_syntax_in(temp_world, node, syntax, temp_env);
+ }
+ serd_env_free(temp_env);
+ }
+
+ serd_world_free(temp_world);
+ return string;
+}