aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/serdi.18
-rw-r--r--include/serd/serd.h118
-rw-r--r--src/.clang-tidy1
-rw-r--r--src/byte_sink.c108
-rw-r--r--src/byte_sink.h75
-rw-r--r--src/serdi.c46
-rw-r--r--src/writer.c28
-rw-r--r--test/meson.build9
-rwxr-xr-xtest/run_test_suite.py8
-rw-r--r--test/test_byte_sink.c32
-rw-r--r--test/test_reader_writer.c17
-rw-r--r--test/test_terse_write.c8
-rw-r--r--test/test_writer.c75
13 files changed, 318 insertions, 215 deletions
diff --git a/doc/serdi.1 b/doc/serdi.1
index bc8de6cb..7c665aff 100644
--- a/doc/serdi.1
+++ b/doc/serdi.1
@@ -14,12 +14,13 @@
.Op Fl p Ar prefix
.Op Fl r Ar root
.Op Fl s Ar string
+.Op Fl w Ar filename
.Ar input
.Op Ar base_uri
.Sh DESCRIPTION
.Nm
is a fast command-line utility for streaming and processing RDF data.
-It reads an RDF document and writes the data to stdout,
+It reads an RDF document and writes the data again,
possibly transformed and/or in a different syntax.
By default,
the input syntax is guessed from the file extension,
@@ -125,6 +126,11 @@ Write terser output without newlines.
.Pp
.It Fl v
Display version information and exit.
+.Pp
+.It Fl w Ar filename
+Write output to the given
+.Ar filename
+instead of stdout.
.El
.Sh EXIT STATUS
.Nm
diff --git a/include/serd/serd.h b/include/serd/serd.h
index 776bf910..95555013 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -305,50 +305,6 @@ typedef size_t (*SerdWriteFunc)(const void* SERD_NONNULL buf,
/**
@}
- @defgroup serd_streams Byte Streams
- @{
-*/
-
-/// A sink for bytes that receives text output
-typedef struct SerdByteSinkImpl SerdByteSink;
-
-/**
- Create a new byte sink.
-
- @param write_func Function called with bytes to consume.
- @param stream Context parameter passed to `sink`.
- @param block_size Number of bytes to write per call.
-*/
-SERD_API
-SerdByteSink* SERD_ALLOCATED
-serd_byte_sink_new(SerdWriteFunc SERD_NONNULL write_func,
- void* SERD_NULLABLE stream,
- size_t block_size);
-
-/**
- Write to `sink`.
-
- Compatible with SerdWriteFunc.
-*/
-SERD_API
-size_t
-serd_byte_sink_write(const void* SERD_NONNULL buf,
- size_t size,
- size_t nmemb,
- SerdByteSink* SERD_NONNULL sink);
-
-/// Flush any pending output in `sink` to the underlying write function
-SERD_API
-void
-serd_byte_sink_flush(SerdByteSink* SERD_NONNULL sink);
-
-/// Free `sink`
-SERD_API
-void
-serd_byte_sink_free(SerdByteSink* SERD_NULLABLE sink);
-
-/**
- @}
@defgroup serd_syntax Syntax Utilities
@{
*/
@@ -1591,6 +1547,77 @@ serd_reader_free(SerdReader* SERD_NULLABLE reader);
/**
@}
+ @defgroup serd_byte_sink Byte Sink
+ @{
+*/
+
+/// A sink for bytes that receives text output
+typedef struct SerdByteSinkImpl SerdByteSink;
+
+/**
+ Create a new byte sink that writes to a buffer.
+
+ The `buffer` is owned by the caller, but will be expanded as necessary.
+
+ @param buffer Buffer to write output to.
+*/
+SERD_API
+SerdByteSink* SERD_ALLOCATED
+serd_byte_sink_new_buffer(SerdBuffer* SERD_NONNULL buffer);
+
+/**
+ Create a new byte sink that writes to a file.
+
+ An arbitrary `FILE*` can be used via serd_byte_sink_new_function() as well,
+ this is just a convenience function that opens the file properly and sets
+ flags for optimized I/O if possible.
+
+ @param path Path of file to open and write to.
+ @param block_size Number of bytes to write per call.
+*/
+SERD_API
+SerdByteSink* SERD_ALLOCATED
+serd_byte_sink_new_filename(const char* SERD_NONNULL path, size_t block_size);
+
+/**
+ Create a new byte sink that writes to a user-specified function.
+
+ The `stream` will be passed to the `write_func`, which is compatible with
+ the standard C `fwrite` if `stream` is a `FILE*`.
+
+ @param write_func Function called with bytes to consume.
+ @param stream Context parameter passed to `sink`.
+ @param block_size Number of bytes to write per call.
+*/
+SERD_API
+SerdByteSink* SERD_ALLOCATED
+serd_byte_sink_new_function(SerdWriteFunc SERD_NONNULL write_func,
+ void* SERD_NULLABLE stream,
+ size_t block_size);
+
+/// Flush any pending output in `sink` to the underlying write function
+SERD_API
+void
+serd_byte_sink_flush(SerdByteSink* SERD_NONNULL sink);
+
+/**
+ Close `sink`, including the underlying file if necessary.
+
+ If `sink` was created with serd_byte_sink_new_filename(), then the file is
+ closed. If there was an error, then SERD_ERR_UNKNOWN is returned and
+ `errno` is set.
+*/
+SERD_API
+SerdStatus
+serd_byte_sink_close(SerdByteSink* SERD_NONNULL sink);
+
+/// Free `sink`, flushing and closing first if necessary
+SERD_API
+void
+serd_byte_sink_free(SerdByteSink* SERD_NULLABLE sink);
+
+/**
+ @}
@defgroup serd_writer Writer
@{
*/
@@ -1623,8 +1650,7 @@ serd_writer_new(SerdWorld* SERD_NONNULL world,
SerdSyntax syntax,
SerdWriterFlags flags,
SerdEnv* SERD_NONNULL env,
- SerdWriteFunc SERD_NONNULL write_func,
- void* SERD_NULLABLE stream);
+ SerdByteSink* SERD_NONNULL byte_sink);
/// Free `writer`
SERD_API
diff --git a/src/.clang-tidy b/src/.clang-tidy
index d39ee7e8..a9e25a2f 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -3,6 +3,7 @@ Checks: >
-*-magic-numbers,
-*-uppercase-literal-suffix,
-altera-*,
+ -android-cloexec-fopen,
-bugprone-branch-clone,
-bugprone-easily-swappable-parameters,
-bugprone-reserved-identifier,
diff --git a/src/byte_sink.c b/src/byte_sink.c
index 6436f9d8..e93e5a07 100644
--- a/src/byte_sink.c
+++ b/src/byte_sink.c
@@ -14,32 +14,46 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "serd_internal.h"
+#include "byte_sink.h"
+
+#include "serd_config.h"
#include "system.h"
#include "serd/serd.h"
-#include <assert.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-struct SerdByteSinkImpl {
- SerdWriteFunc sink;
- void* stream;
- char* buf;
- size_t size;
- size_t block_size;
-};
+#if USE_POSIX_FADVISE && USE_FILENO
+# include <fcntl.h>
+#endif
SerdByteSink*
-serd_byte_sink_new(SerdWriteFunc write_func, void* stream, size_t block_size)
+serd_byte_sink_new_buffer(SerdBuffer* const buffer)
{
SerdByteSink* sink = (SerdByteSink*)calloc(1, sizeof(SerdByteSink));
- sink->sink = write_func;
+ sink->write_func = serd_buffer_sink;
+ sink->stream = buffer;
+ sink->block_size = 1;
+ sink->type = TO_BUFFER;
+
+ return sink;
+}
+
+static SerdByteSink*
+serd_byte_sink_new_internal(const SerdWriteFunc write_func,
+ void* const stream,
+ const size_t block_size,
+ const SerdByteSinkType type)
+{
+ SerdByteSink* sink = (SerdByteSink*)calloc(1, sizeof(SerdByteSink));
+
+ sink->write_func = write_func;
sink->stream = stream;
sink->block_size = block_size;
+ sink->type = type;
if (block_size > 1) {
sink->buf = (char*)serd_allocate_buffer(block_size);
@@ -48,58 +62,64 @@ serd_byte_sink_new(SerdWriteFunc write_func, void* stream, size_t block_size)
return sink;
}
-size_t
-serd_byte_sink_write(const void* buf,
- size_t size,
- size_t nmemb,
- SerdByteSink* sink)
+SerdByteSink*
+serd_byte_sink_new_filename(const char* const path, const size_t block_size)
{
- assert(size == 1);
- (void)size;
-
- if (nmemb == 0) {
- return 0;
+ if (!block_size) {
+ return NULL;
}
- if (sink->block_size == 1) {
- return sink->sink(buf, 1, nmemb, sink->stream);
+ FILE* const file = fopen(path, "wb");
+ if (!file) {
+ return NULL;
}
- const size_t orig_len = nmemb;
- while (nmemb) {
- const size_t space = sink->block_size - sink->size;
- const size_t n = MIN(space, nmemb);
-
- // Write as much as possible into the remaining buffer space
- memcpy(sink->buf + sink->size, buf, n);
- sink->size += n;
- buf = (const char*)buf + n;
- nmemb -= n;
-
- // Flush page if buffer is full
- if (sink->size == sink->block_size) {
- sink->sink(sink->buf, 1, sink->block_size, sink->stream);
- sink->size = 0;
- }
- }
+#if USE_POSIX_FADVISE && USE_FILENO
+ posix_fadvise(fileno(file), 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
- return orig_len;
+ return serd_byte_sink_new_internal(
+ (SerdWriteFunc)fwrite, file, block_size, TO_FILENAME);
+}
+
+SerdByteSink*
+serd_byte_sink_new_function(const SerdWriteFunc write_func,
+ void* const stream,
+ const size_t block_size)
+{
+ return block_size ? serd_byte_sink_new_internal(
+ write_func, stream, block_size, TO_FUNCTION)
+ : NULL;
}
void
serd_byte_sink_flush(SerdByteSink* sink)
{
if (sink->block_size > 1 && sink->size > 0) {
- sink->sink(sink->buf, 1, sink->size, sink->stream);
+ sink->write_func(sink->buf, 1, sink->size, sink->stream);
sink->size = 0;
}
}
+SerdStatus
+serd_byte_sink_close(SerdByteSink* sink)
+{
+ serd_byte_sink_flush(sink);
+
+ if (sink->type == TO_FILENAME && sink->stream) {
+ const int st = fclose((FILE*)sink->stream);
+ sink->stream = NULL;
+ return st ? SERD_ERR_UNKNOWN : SERD_SUCCESS;
+ }
+
+ return SERD_SUCCESS;
+}
+
void
serd_byte_sink_free(SerdByteSink* const sink)
{
if (sink) {
- serd_byte_sink_flush(sink);
+ serd_byte_sink_close(sink);
serd_free_aligned(sink->buf);
free(sink);
}
diff --git a/src/byte_sink.h b/src/byte_sink.h
index 576f9c2e..f023f180 100644
--- a/src/byte_sink.h
+++ b/src/byte_sink.h
@@ -17,80 +17,55 @@
#ifndef SERD_BYTE_SINK_H
#define SERD_BYTE_SINK_H
-#include "serd_internal.h"
-#include "system.h"
-
#include "serd/serd.h"
#include <stddef.h>
#include <string.h>
-typedef struct SerdByteSinkImpl {
- SerdWriteFunc sink;
- void* stream;
- char* buf;
- size_t size;
- size_t block_size;
-} SerdByteSink;
-
-static inline SerdByteSink
-serd_byte_sink_new(SerdWriteFunc sink, void* stream, size_t block_size)
-{
- SerdByteSink bsink;
- bsink.sink = sink;
- bsink.stream = stream;
- bsink.size = 0;
- bsink.block_size = block_size;
- bsink.buf =
- ((block_size > 1) ? (char*)serd_allocate_buffer(block_size) : NULL);
- return bsink;
-}
-
-static inline void
-serd_byte_sink_flush(SerdByteSink* bsink)
-{
- if (bsink->block_size > 1 && bsink->size > 0) {
- bsink->sink(bsink->buf, 1, bsink->size, bsink->stream);
- bsink->size = 0;
- }
-}
-
-static inline void
-serd_byte_sink_free(SerdByteSink* bsink)
-{
- serd_byte_sink_flush(bsink);
- serd_free_aligned(bsink->buf);
- bsink->buf = NULL;
-}
+typedef enum {
+ TO_BUFFER, ///< Writing to a user-provided buffer
+ TO_FILENAME, ///< Writing to a file we opened
+ TO_FUNCTION, ///< Writing to a user-provided function
+} SerdByteSinkType;
+
+struct SerdByteSinkImpl {
+ SerdWriteFunc write_func; ///< User sink for TO_FUNCTION
+ void* stream; ///< User data for write_func
+ char* buf; ///< Local buffer iff block_size > 1
+ size_t size; ///< Bytes written so far in this chunk
+ size_t block_size; ///< Size of chunks to write
+ SerdByteSinkType type; ///< Type of output
+};
static inline size_t
-serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* bsink)
+serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* const sink)
{
if (len == 0) {
return 0;
}
- if (bsink->block_size == 1) {
- return bsink->sink(buf, 1, len, bsink->stream);
+ if (sink->block_size == 1) {
+ return sink->write_func(buf, 1, len, sink->stream);
}
const size_t orig_len = len;
while (len) {
- const size_t space = bsink->block_size - bsink->size;
- const size_t n = MIN(space, len);
+ const size_t space = sink->block_size - sink->size;
+ const size_t n = space < len ? space : len;
// Write as much as possible into the remaining buffer space
- memcpy(bsink->buf + bsink->size, buf, n);
- bsink->size += n;
+ memcpy(sink->buf + sink->size, buf, n);
+ sink->size += n;
buf = (const char*)buf + n;
len -= n;
// Flush page if buffer is full
- if (bsink->size == bsink->block_size) {
- bsink->sink(bsink->buf, 1, bsink->block_size, bsink->stream);
- bsink->size = 0;
+ if (sink->size == sink->block_size) {
+ sink->write_func(sink->buf, 1, sink->block_size, sink->stream);
+ sink->size = 0;
}
}
+
return orig_len;
}
diff --git a/src/serdi.c b/src/serdi.c
index 74b8cad4..ea6bb22b 100644
--- a/src/serdi.c
+++ b/src/serdi.c
@@ -71,6 +71,7 @@ print_usage(const char* const name, const bool error)
fprintf(os, " -s INPUT Parse INPUT as string (terminates options).\n");
fprintf(os, " -t Write terser output without newlines.\n");
fprintf(os, " -v Display version information and exit.\n");
+ fprintf(os, " -w FILENAME Write output to FILENAME instead of stdout.\n");
return error ? 1 : 0;
}
@@ -111,6 +112,7 @@ main(int argc, char** argv)
const char* add_prefix = NULL;
const char* chop_prefix = NULL;
const char* root_uri = NULL;
+ const char* out_filename = NULL;
int a = 1;
for (; a < argc && !from_string && argv[a][0] == '-'; ++a) {
if (argv[a][1] == '\0') {
@@ -198,6 +200,13 @@ main(int argc, char** argv)
root_uri = argv[a];
break;
+ } else if (opt == 'w') {
+ if (argv[a][o + 1] || ++a == argc) {
+ return missing_arg(argv[0], 'w');
+ }
+
+ out_filename = argv[a];
+ break;
} else {
SERDI_ERRORF("invalid option -- '%s'\n", argv[a] + 1);
return print_usage(prog, true);
@@ -210,11 +219,6 @@ main(int argc, char** argv)
return 1;
}
-#ifdef _WIN32
- _setmode(_fileno(stdin), _O_BINARY);
- _setmode(_fileno(stdout), _O_BINARY);
-#endif
-
const char* input = argv[a++];
if (!input_syntax && !(input_syntax = serd_guess_syntax(input))) {
@@ -233,21 +237,30 @@ main(int argc, char** argv)
base = serd_new_file_uri(SERD_STRING(input), SERD_EMPTY_STRING());
}
- FILE* const out_fd = stdout;
- SerdWorld* const world = serd_world_new();
+ SerdWorld* const world = serd_world_new();
SerdEnv* const env =
serd_env_new(base ? serd_node_string_view(base) : SERD_EMPTY_STRING());
+#ifdef _WIN32
+ _setmode(_fileno(stdin), _O_BINARY);
+ if (!out_filename) {
+ _setmode(_fileno(stdout), _O_BINARY);
+ }
+#endif
+
+ const size_t block_size = bulk_write ? 4096u : 1u;
SerdByteSink* const byte_sink =
- serd_byte_sink_new((SerdWriteFunc)fwrite, out_fd, bulk_write ? 4096u : 1u);
+ out_filename
+ ? serd_byte_sink_new_filename(out_filename, block_size)
+ : serd_byte_sink_new_function((SerdWriteFunc)fwrite, stdout, block_size);
+
+ if (!byte_sink) {
+ perror("serdi: error opening output file");
+ return 1;
+ }
SerdWriter* const writer =
- serd_writer_new(world,
- output_syntax,
- writer_flags,
- env,
- (SerdWriteFunc)serd_byte_sink_write,
- byte_sink);
+ serd_writer_new(world, output_syntax, writer_flags, env, byte_sink);
SerdReader* const reader =
serd_reader_new(world, input_syntax, serd_writer_sink(writer), stack_size);
@@ -291,15 +304,16 @@ main(int argc, char** argv)
serd_reader_free(reader);
serd_writer_free(writer);
serd_node_free(input_name);
- serd_byte_sink_free(byte_sink);
serd_env_free(env);
serd_node_free(base);
serd_world_free(world);
- if (fclose(stdout)) {
+ if (serd_byte_sink_close(byte_sink) || (!out_filename && fclose(stdout))) {
perror("serdi: write error");
st = SERD_ERR_UNKNOWN;
}
+ serd_byte_sink_free(byte_sink);
+
return (st > SERD_FAILURE) ? 1 : 0;
}
diff --git a/src/writer.c b/src/writer.c
index 3e0faa1e..3606fe44 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -14,6 +14,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "byte_sink.h"
#include "env.h"
#include "node.h"
#include "serd_internal.h"
@@ -130,8 +131,7 @@ struct SerdWriterImpl {
SerdURIView root_uri;
WriteContext* anon_stack;
size_t anon_stack_size;
- SerdWriteFunc write_func;
- void* stream;
+ SerdByteSink* byte_sink;
WriteContext context;
char* bprefix;
size_t bprefix_len;
@@ -225,7 +225,7 @@ ctx(SerdWriter* writer, const SerdField field)
SERD_WARN_UNUSED_RESULT static size_t
sink(const void* buf, size_t len, SerdWriter* writer)
{
- const size_t written = writer->write_func(buf, 1, len, writer->stream);
+ const size_t written = serd_byte_sink_write(buf, len, writer->byte_sink);
if (written != len) {
if (errno) {
char message[1024] = {0};
@@ -1134,22 +1134,20 @@ serd_writer_new(SerdWorld* world,
SerdSyntax syntax,
SerdWriterFlags flags,
SerdEnv* env,
- SerdWriteFunc write_func,
- void* stream)
+ SerdByteSink* byte_sink)
{
const WriteContext context = WRITE_CONTEXT_NULL;
SerdWriter* writer = (SerdWriter*)calloc(1, sizeof(SerdWriter));
- writer->world = world;
- writer->syntax = syntax;
- writer->flags = flags;
- writer->env = env;
- writer->root_node = NULL;
- writer->root_uri = SERD_URI_NULL;
- writer->write_func = write_func;
- writer->stream = stream;
- writer->context = context;
- writer->empty = true;
+ writer->world = world;
+ writer->syntax = syntax;
+ writer->flags = flags;
+ writer->env = env;
+ writer->root_node = NULL;
+ writer->root_uri = SERD_URI_NULL;
+ writer->byte_sink = byte_sink;
+ writer->context = context;
+ writer->empty = true;
writer->anon_stack =
(WriteContext*)calloc(anon_stack_capacity, sizeof(WriteContext));
diff --git a/test/meson.build b/test/meson.build
index 9724f18e..1245e29d 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -5,6 +5,7 @@ run_test_suite = find_program('run_test_suite.py')
wrapper = meson.get_cross_property('exe_wrapper', '')
unit_tests = [
+ 'byte_sink',
'caret',
'env',
'free_null',
@@ -83,6 +84,7 @@ if get_option('utils')
['-o'],
['-p'],
['-r'],
+ ['-w'],
['-z'],
['-s', '<foo> a <Bar> .'],
]
@@ -166,6 +168,13 @@ if get_option('utils')
env: test_env,
suite: 'io_errors')
+ test('write_bad_file', serdi,
+ args: ['-w', '/does/not/exist.ttl',
+ 'file://@0@/serd.ttl'.format(meson.source_root())],
+ env: test_env,
+ should_fail: true,
+ suite: 'io_errors')
+
# RDF test suites
## Serd-specific test suites
diff --git a/test/run_test_suite.py b/test/run_test_suite.py
index 5223060d..7a3b5e88 100755
--- a/test/run_test_suite.py
+++ b/test/run_test_suite.py
@@ -83,6 +83,8 @@ def test_thru(
isyntax,
"-p",
"foo",
+ "-w",
+ out_path,
path,
base_uri,
]
@@ -98,14 +100,16 @@ def test_thru(
osyntax,
"-c",
"foo",
+ "-w",
+ thru_path,
"-a",
out_path,
base_uri,
]
)
- with open(out_path, "wb") as out:
- subprocess.run(out_cmd, check=True, stdout=out)
+ subprocess.run(out_cmd, check=True)
+ subprocess.run(thru_cmd, check=True)
with open(thru_path, "wb") as out:
subprocess.run(thru_cmd, check=True, stdout=out)
diff --git a/test/test_byte_sink.c b/test/test_byte_sink.c
new file mode 100644
index 00000000..1982a436
--- /dev/null
+++ b/test/test_byte_sink.c
@@ -0,0 +1,32 @@
+/*
+ Copyright 2021 David Robillard <d@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.
+*/
+
+#undef NDEBUG
+
+#include "serd/serd.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+int
+main(void)
+{
+ assert(!serd_byte_sink_new_filename("file.ttl", 0));
+ assert(!serd_byte_sink_new_filename("/does/not/exist.ttl", 1));
+ assert(!serd_byte_sink_new_function((SerdWriteFunc)fwrite, NULL, 0));
+
+ return 0;
+}
diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c
index 3f538ada..82d67bee 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -178,8 +178,12 @@ test_writer(const char* const path)
SerdWorld* world = serd_world_new();
SerdNodes* nodes = serd_world_nodes(world);
- SerdWriter* writer = serd_writer_new(
- world, SERD_TURTLE, SERD_WRITE_LAX, env, (SerdWriteFunc)fwrite, fd);
+ SerdByteSink* byte_sink =
+ serd_byte_sink_new_function((SerdWriteFunc)fwrite, fd, 1);
+
+ SerdWriter* writer =
+ serd_writer_new(world, SERD_TURTLE, SERD_WRITE_LAX, env, byte_sink);
+
assert(writer);
serd_writer_chop_blank_prefix(writer, "tmp");
@@ -240,14 +244,13 @@ test_writer(const char* const path)
assert(!serd_sink_write(iface, 0, s, p, hello, 0));
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
// Test buffer sink
- SerdBuffer buffer = {NULL, 0};
- SerdByteSink* byte_sink =
- serd_byte_sink_new((SerdWriteFunc)serd_buffer_sink, &buffer, 1);
+ SerdBuffer buffer = {NULL, 0};
- writer = serd_writer_new(
- world, SERD_TURTLE, 0, env, (SerdWriteFunc)serd_byte_sink_write, byte_sink);
+ byte_sink = serd_byte_sink_new_buffer(&buffer);
+ writer = serd_writer_new(world, SERD_TURTLE, 0, env, byte_sink);
const SerdNode* const base =
serd_nodes_uri(nodes, SERD_STRING("http://example.org/base"));
diff --git a/test/test_terse_write.c b/test/test_terse_write.c
index 9a19d493..59227332 100644
--- a/test/test_terse_write.c
+++ b/test/test_terse_write.c
@@ -64,10 +64,11 @@ test(void)
serd_env_set_prefix(env, SERD_STRING("rdf"), SERD_STRING(NS_RDF));
- SerdWriter* writer = serd_writer_new(
- world, SERD_TURTLE, 0, env, (SerdWriteFunc)serd_buffer_sink, &buffer);
+ SerdByteSink* const byte_sink = serd_byte_sink_new_buffer(&buffer);
+ SerdWriter* const writer =
+ serd_writer_new(world, SERD_TURTLE, 0, env, byte_sink);
- const SerdSink* sink = serd_writer_sink(writer);
+ const SerdSink* const sink = serd_writer_sink(writer);
// Simple lone list
serd_sink_write(sink, SERD_TERSE_S | SERD_LIST_S, l1, rdf_first, s1, NULL);
@@ -99,6 +100,7 @@ test(void)
serd_buffer_sink_finish(&buffer);
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
serd_nodes_free(nodes);
serd_env_free(env);
serd_world_free(world);
diff --git a/test/test_writer.c b/test/test_writer.c
index e31119bf..df8ba520 100644
--- a/test/test_writer.c
+++ b/test/test_writer.c
@@ -27,12 +27,12 @@
static void
test_write_bad_event(void)
{
- SerdWorld* world = serd_world_new();
- SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
- SerdBuffer buffer = {NULL, 0};
- SerdWriter* writer =
- serd_writer_new(world, SERD_TURTLE, 0u, env, serd_buffer_sink, &buffer);
+ SerdWorld* world = serd_world_new();
+ SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
+ SerdBuffer buffer = {NULL, 0};
+ SerdByteSink* byte_sink = serd_byte_sink_new_buffer(&buffer);
+ SerdWriter* writer = serd_writer_new(world, SERD_TURTLE, 0u, env, byte_sink);
assert(writer);
const SerdEvent event = {(SerdEventType)42};
@@ -45,6 +45,7 @@ test_write_bad_event(void)
serd_free(out);
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
serd_env_free(env);
serd_world_free(world);
}
@@ -52,13 +53,13 @@ test_write_bad_event(void)
static void
test_write_bad_prefix(void)
{
- SerdWorld* world = serd_world_new();
- SerdNodes* nodes = serd_world_nodes(world);
- SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
- SerdBuffer buffer = {NULL, 0};
- SerdWriter* writer =
- serd_writer_new(world, SERD_TURTLE, 0u, env, serd_buffer_sink, &buffer);
+ SerdWorld* world = serd_world_new();
+ SerdNodes* nodes = serd_world_nodes(world);
+ SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
+ SerdBuffer buffer = {NULL, 0};
+ SerdByteSink* byte_sink = serd_byte_sink_new_buffer(&buffer);
+ SerdWriter* writer = serd_writer_new(world, SERD_TURTLE, 0u, env, byte_sink);
assert(writer);
const SerdNode* name = serd_nodes_string(nodes, SERD_STRING("eg"));
@@ -73,6 +74,7 @@ test_write_bad_prefix(void)
serd_free(out);
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
serd_env_free(env);
serd_world_free(world);
}
@@ -80,13 +82,13 @@ test_write_bad_prefix(void)
static void
test_write_long_literal(void)
{
- SerdWorld* world = serd_world_new();
- SerdNodes* nodes = serd_world_nodes(world);
- SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
- SerdBuffer buffer = {NULL, 0};
- SerdWriter* writer =
- serd_writer_new(world, SERD_TURTLE, 0u, env, serd_buffer_sink, &buffer);
+ SerdWorld* world = serd_world_new();
+ SerdNodes* nodes = serd_world_nodes(world);
+ SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
+ SerdBuffer buffer = {NULL, 0};
+ SerdByteSink* byte_sink = serd_byte_sink_new_buffer(&buffer);
+ SerdWriter* writer = serd_writer_new(world, SERD_TURTLE, 0u, env, byte_sink);
assert(writer);
const SerdNode* s =
@@ -99,6 +101,7 @@ test_write_long_literal(void)
assert(!serd_sink_write(serd_writer_sink(writer), 0, s, p, o, NULL));
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
serd_env_free(env);
char* out = serd_buffer_sink_finish(&buffer);
@@ -128,12 +131,12 @@ null_sink(const void* const buf,
static void
test_writer_stack_overflow(void)
{
- SerdWorld* world = serd_world_new();
- SerdNodes* nodes = serd_world_nodes(world);
- SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
+ SerdWorld* world = serd_world_new();
+ SerdNodes* nodes = serd_world_nodes(world);
+ SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
+ SerdByteSink* byte_sink = serd_byte_sink_new_function(null_sink, NULL, 1u);
- SerdWriter* writer =
- serd_writer_new(world, SERD_TURTLE, 0u, env, null_sink, NULL);
+ SerdWriter* writer = serd_writer_new(world, SERD_TURTLE, 0u, env, byte_sink);
const SerdSink* sink = serd_writer_sink(writer);
@@ -168,6 +171,7 @@ test_writer_stack_overflow(void)
assert(st == SERD_ERR_OVERFLOW);
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
serd_env_free(env);
serd_world_free(world);
}
@@ -181,10 +185,12 @@ test_strict_write(void)
FILE* fd = fopen(path, "wb");
assert(fd);
- SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
- SerdWriter* writer =
- serd_writer_new(world, SERD_TURTLE, 0u, env, (SerdWriteFunc)fwrite, fd);
+ SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
+
+ SerdByteSink* byte_sink =
+ serd_byte_sink_new_function((SerdWriteFunc)fwrite, fd, 1);
+ SerdWriter* writer = serd_writer_new(world, SERD_TURTLE, 0, env, byte_sink);
assert(writer);
const SerdSink* sink = serd_writer_sink(writer);
@@ -204,6 +210,7 @@ test_strict_write(void)
assert(serd_sink_write(sink, 0, s, p, bad_uri, 0) == SERD_ERR_BAD_TEXT);
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
serd_env_free(env);
fclose(fd);
serd_world_free(world);
@@ -245,18 +252,20 @@ test_write_error(void)
// Test with setting errno
- SerdWriter* writer =
- serd_writer_new(world, SERD_TURTLE, 0u, env, faulty_sink, NULL);
+ SerdByteSink* byte_sink = serd_byte_sink_new_function(faulty_sink, NULL, 1);
+ SerdWriter* writer = serd_writer_new(world, SERD_TURTLE, 0u, env, byte_sink);
assert(writer);
SerdStatus st = serd_sink_write(serd_writer_sink(writer), 0u, s, p, o, NULL);
assert(st == SERD_ERR_BAD_WRITE);
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
// Test without setting errno
- writer = serd_writer_new(world, SERD_TURTLE, 0u, env, faulty_sink, world);
+ byte_sink = serd_byte_sink_new_function(faulty_sink, world, 1);
+ writer = serd_writer_new(world, SERD_TURTLE, 0u, env, byte_sink);
assert(writer);
@@ -264,6 +273,7 @@ test_write_error(void)
SERD_ERR_BAD_WRITE);
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
serd_env_free(env);
serd_world_free(world);
@@ -278,15 +288,17 @@ test_write_empty_syntax(void)
const SerdNode* s =
serd_nodes_uri(nodes, SERD_STRING("http://example.org/s"));
+
const SerdNode* p =
serd_nodes_uri(nodes, SERD_STRING("http://example.org/p"));
const SerdNode* o = serd_nodes_curie(nodes, SERD_STRING("eg:o"));
- SerdBuffer buffer = {NULL, 0};
+ SerdBuffer buffer = {NULL, 0};
+ SerdByteSink* byte_sink = serd_byte_sink_new_buffer(&buffer);
- SerdWriter* writer = serd_writer_new(
- world, SERD_SYNTAX_EMPTY, 0u, env, serd_buffer_sink, &buffer);
+ SerdWriter* writer =
+ serd_writer_new(world, SERD_SYNTAX_EMPTY, 0u, env, byte_sink);
assert(writer);
@@ -298,6 +310,7 @@ test_write_empty_syntax(void)
serd_free(out);
serd_writer_free(writer);
+ serd_byte_sink_free(byte_sink);
serd_env_free(env);
serd_world_free(world);
}