diff options
-rw-r--r-- | serd/serd.h | 63 | ||||
-rw-r--r-- | src/n3.c | 1 | ||||
-rw-r--r-- | src/reader.c | 1 | ||||
-rw-r--r-- | src/sink.c | 62 | ||||
-rw-r--r-- | src/sink.h | 33 | ||||
-rw-r--r-- | src/writer.c | 1 | ||||
-rw-r--r-- | tests/free_null_test.c | 1 | ||||
-rw-r--r-- | tests/read_chunk_test.c | 13 | ||||
-rw-r--r-- | tests/serd_test.c | 35 |
9 files changed, 175 insertions, 35 deletions
diff --git a/serd/serd.h b/serd/serd.h index be3ea586..deef03da 100644 --- a/serd/serd.h +++ b/serd/serd.h @@ -103,6 +103,11 @@ typedef struct SerdReaderImpl SerdReader; typedef struct SerdWriterImpl SerdWriter; /** + An interface that receives a stream of RDF data. +*/ +typedef struct SerdSinkImpl SerdSink; + +/** Return status code. */ typedef enum { @@ -831,17 +836,6 @@ typedef SerdStatus (*SerdEndSink)(void* handle, const SerdNode* node); /** - An interface that receives a stream of RDF data. -*/ -typedef struct SerdSink { - void* handle; - SerdBaseSink base; - SerdPrefixSink prefix; - SerdStatementSink statement; - SerdEndSink end; -} SerdSink; - -/** @} @name World @{ @@ -970,6 +964,53 @@ serd_env_foreach(const SerdEnv* env, */ /** + Create a new sink. + + Initially, the sink has no set functions and will do nothing. Use the + serd_sink_set_*_func functions to set handlers for various events. + + @param handle Opaque handle that will be passed to sink functions. +*/ +SERD_API +SerdSink* +serd_sink_new(void* handle); + +/** + Free `sink`. +*/ +SERD_API +void +serd_sink_free(SerdSink* sink); + +/** + Set a function to be called when the base URI changes. +*/ +SERD_API +SerdStatus +serd_sink_set_base_func(SerdSink* sink, SerdBaseSink base_func); + +/** + Set a function to be called when a namespace prefix is defined. +*/ +SERD_API +SerdStatus +serd_sink_set_prefix_func(SerdSink* sink, SerdPrefixSink prefix_func); + +/** + Set a function to be called when a statement is emitted. +*/ +SERD_API +SerdStatus +serd_sink_set_statement_func(SerdSink* sink, SerdStatementSink statement_func); + +/** + Set a function to be called when an anonymous node ends. +*/ +SERD_API +SerdStatus +serd_sink_set_end_func(SerdSink* sink, SerdEndSink end_func); + +/** Set the base URI. Simple wrapper for the `SerdBaseSink` of `sink`. @@ -18,6 +18,7 @@ #include "node.h" #include "reader.h" #include "serd_internal.h" +#include "sink.h" #include "stack.h" #include "string_utils.h" #include "uri_utils.h" diff --git a/src/reader.c b/src/reader.c index f8cd27be..b92d1e5a 100644 --- a/src/reader.c +++ b/src/reader.c @@ -18,6 +18,7 @@ #include "system.h" #include "serd_internal.h" +#include "sink.h" #include "statement.h" #include "world.h" @@ -1,5 +1,5 @@ /* - Copyright 2011-2018 David Robillard <http://drobilla.net> + Copyright 2011-2020 David Robillard <http://drobilla.net> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -14,16 +14,61 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "serd/serd.h" +#include "sink.h" #include "statement.h" -#include <stddef.h> +#include "serd/serd.h" + +#include <stdlib.h> + +SerdSink* +serd_sink_new(void* handle) +{ + SerdSink* sink = (SerdSink*)calloc(1, sizeof(SerdSink)); + + sink->handle = handle; + return sink; +} + +void +serd_sink_free(SerdSink* sink) +{ + free(sink); +} + +SerdStatus +serd_sink_set_base_func(SerdSink* sink, SerdBaseSink base_func) +{ + sink->base = base_func; + return SERD_SUCCESS; +} + +SerdStatus +serd_sink_set_prefix_func(SerdSink* sink, SerdPrefixSink prefix_func) +{ + sink->prefix = prefix_func; + return SERD_SUCCESS; +} + +SerdStatus +serd_sink_set_statement_func(SerdSink* sink, SerdStatementSink statement_func) +{ + sink->statement = statement_func; + return SERD_SUCCESS; +} + +SerdStatus +serd_sink_set_end_func(SerdSink* sink, SerdEndSink end_func) +{ + sink->end = end_func; + return SERD_SUCCESS; +} SerdStatus serd_sink_write_base(const SerdSink* sink, const SerdNode* uri) { - return sink->base(sink->handle, uri); + return sink->base ? sink->base(sink->handle, uri) : SERD_SUCCESS; } SerdStatus @@ -31,7 +76,7 @@ serd_sink_write_prefix(const SerdSink* sink, const SerdNode* name, const SerdNode* uri) { - return sink->prefix(sink->handle, name, uri); + return sink->prefix ? sink->prefix(sink->handle, name, uri) : SERD_SUCCESS; } SerdStatus @@ -39,7 +84,8 @@ serd_sink_write_statement(const SerdSink* sink, const SerdStatementFlags flags, const SerdStatement* statement) { - return sink->statement(sink->handle, flags, statement); + return sink->statement ? sink->statement(sink->handle, flags, statement) + : SERD_SUCCESS; } SerdStatus @@ -52,11 +98,11 @@ serd_sink_write(const SerdSink* sink, { const SerdStatement statement = { { subject, predicate, object, graph }, NULL }; - return sink->statement(sink->handle, flags, &statement); + return serd_sink_write_statement(sink, flags, &statement); } SerdStatus serd_sink_write_end(const SerdSink* sink, const SerdNode* node) { - return sink->end(sink->handle, node); + return sink->end ? sink->end(sink->handle, node) : SERD_SUCCESS; } diff --git a/src/sink.h b/src/sink.h new file mode 100644 index 00000000..25dfb079 --- /dev/null +++ b/src/sink.h @@ -0,0 +1,33 @@ +/* + Copyright 2011-2020 David Robillard <http://drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef SERD_SINK_H +#define SERD_SINK_H + +#include "serd/serd.h" + +/** + An interface that receives a stream of RDF data. +*/ +struct SerdSinkImpl { + void* handle; + SerdBaseSink base; + SerdPrefixSink prefix; + SerdStatementSink statement; + SerdEndSink end; +}; + +#endif // SERD_SINK_H diff --git a/src/writer.c b/src/writer.c index adfb64b2..4b5b1245 100644 --- a/src/writer.c +++ b/src/writer.c @@ -18,6 +18,7 @@ #include "env.h" #include "node.h" #include "serd_internal.h" +#include "sink.h" #include "stack.h" #include "string_utils.h" #include "uri_utils.h" diff --git a/tests/free_null_test.c b/tests/free_null_test.c index 40f72ba7..1068ca01 100644 --- a/tests/free_null_test.c +++ b/tests/free_null_test.c @@ -27,6 +27,7 @@ main(void) serd_node_free(NULL); serd_world_free(NULL); serd_env_free(NULL); + serd_sink_free(NULL); serd_reader_free(NULL); serd_writer_free(NULL); serd_cursor_free(NULL); diff --git a/tests/read_chunk_test.c b/tests/read_chunk_test.c index 6efdc37f..8ff3e03e 100644 --- a/tests/read_chunk_test.c +++ b/tests/read_chunk_test.c @@ -73,10 +73,14 @@ on_end(void* handle, const SerdNode* node) int main(void) { - SerdWorld* world = serd_world_new(); - const SerdSink sink = {NULL, on_base, on_prefix, on_statement, on_end}; - - SerdReader* reader = serd_reader_new(world, SERD_TURTLE, &sink, 4096); + SerdWorld* world = serd_world_new(); + SerdSink* sink = serd_sink_new(NULL); + serd_sink_set_base_func(sink, on_base); + serd_sink_set_prefix_func(sink, on_prefix); + serd_sink_set_statement_func(sink, on_statement); + serd_sink_set_end_func(sink, on_end); + + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); assert(reader); assert(!serd_reader_start_string(reader, @@ -102,6 +106,7 @@ main(void) assert(serd_reader_read_chunk(reader) == SERD_FAILURE); serd_reader_free(reader); + serd_sink_free(sink); serd_world_free(world); return 0; } diff --git a/tests/serd_test.c b/tests/serd_test.c index 786c92f3..515b0579 100644 --- a/tests/serd_test.c +++ b/tests/serd_test.c @@ -126,12 +126,14 @@ test_read_chunks(void) ReaderTest* const rt = (ReaderTest*)calloc(1, sizeof(ReaderTest)); FILE* const f = tmpfile(); static const char null = 0; - SerdSink sink = {rt, NULL, NULL, test_sink, NULL}; - SerdReader* reader = serd_reader_new(world, SERD_TURTLE, &sink, 4096); + SerdSink* sink = serd_sink_new(rt); + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); assert(reader); assert(f); + serd_sink_set_statement_func(sink, test_sink); + SerdStatus st = serd_reader_start_stream(reader, (SerdReadFunc)fread, (SerdStreamErrorFunc)ferror, @@ -179,6 +181,7 @@ test_read_chunks(void) assert(rt->n_statements == 2); serd_reader_free(reader); + serd_sink_free(sink); fclose(f); free(rt); serd_world_free(world); @@ -204,12 +207,14 @@ test_get_blank(void) static void test_read_string(void) { - SerdWorld* world = serd_world_new(); - ReaderTest* rt = (ReaderTest*)calloc(1, sizeof(ReaderTest)); - SerdSink sink = {rt, NULL, NULL, test_sink, NULL}; - SerdReader* reader = serd_reader_new(world, SERD_TURTLE, &sink, 4096); + SerdWorld* world = serd_world_new(); + ReaderTest* const rt = (ReaderTest*)calloc(1, sizeof(ReaderTest)); + SerdSink* sink = serd_sink_new(rt); + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); assert(reader); + serd_sink_set_statement_func(sink, test_sink); + // Test reading a string that ends exactly at the end of input (no newline) assert(!serd_reader_start_string( reader, @@ -222,6 +227,7 @@ test_read_string(void) assert(!serd_reader_finish(reader)); serd_reader_free(reader); + serd_sink_free(sink); serd_world_free(world); } @@ -602,9 +608,9 @@ test_writer(const char* const path) SerdNode* lit = serd_new_string("hello"); const SerdSink* iface = serd_writer_get_sink(writer); - assert(iface->base(iface->handle, lit)); - assert(iface->prefix(iface->handle, lit, lit)); - assert(iface->end(iface->handle, NULL)); + assert(serd_sink_write_base(iface, lit)); + assert(serd_sink_write_prefix(iface, lit, lit)); + assert(serd_sink_write_end(iface, NULL)); assert(serd_writer_env(writer) == env); uint8_t buf[] = { 0xEF, 0xBF, 0xBD, 0 }; @@ -692,9 +698,12 @@ static void test_reader(const char* path) { SerdWorld* world = serd_world_new(); - ReaderTest rt = { 0, NULL }; - SerdSink sink = { &rt, NULL, NULL, test_sink, NULL }; - SerdReader* reader = serd_reader_new(world, SERD_TURTLE, &sink, 4096); + + ReaderTest rt = { 0, NULL }; + SerdSink* sink = serd_sink_new(&rt); + serd_sink_set_statement_func(sink, test_sink); + + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); assert(reader); SerdNode* g = serd_new_uri("http://example.org/"); @@ -754,6 +763,8 @@ test_reader(const char* path) } serd_reader_free(reader); + serd_sink_free(sink); + serd_world_free(world); } |