// Copyright 2011-2020 David Robillard // 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/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/syntax.h" #include "serd/world.h" #include "serd/writer.h" #include "zix/allocator.h" #include "zix/string_view.h" #include #include #include typedef struct { ZixAllocator* 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 "; ZixAllocator* 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(ZixAllocator* 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, zix_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(ZixAllocator* 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, zix_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; }