diff options
-rw-r--r-- | doc/serdi.1 | 8 | ||||
-rw-r--r-- | include/serd/serd.h | 118 | ||||
-rw-r--r-- | src/.clang-tidy | 1 | ||||
-rw-r--r-- | src/byte_sink.c | 108 | ||||
-rw-r--r-- | src/byte_sink.h | 75 | ||||
-rw-r--r-- | src/serdi.c | 46 | ||||
-rw-r--r-- | src/writer.c | 28 | ||||
-rw-r--r-- | test/meson.build | 9 | ||||
-rwxr-xr-x | test/run_test_suite.py | 8 | ||||
-rw-r--r-- | test/test_byte_sink.c | 32 | ||||
-rw-r--r-- | test/test_reader_writer.c | 17 | ||||
-rw-r--r-- | test/test_terse_write.c | 8 | ||||
-rw-r--r-- | test/test_writer.c | 75 |
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); } |