aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--include/serd/buffer.h7
-rw-r--r--include/serd/reader.h4
-rw-r--r--include/serd/stream.h38
-rw-r--r--include/serd/uri.h6
-rw-r--r--include/serd/writer.h22
-rw-r--r--src/byte_sink.h18
-rw-r--r--src/byte_source.c2
-rw-r--r--src/byte_source.h4
-rw-r--r--src/node.c21
-rw-r--r--src/reader.c8
-rw-r--r--src/serdi.c5
-rw-r--r--src/uri.c33
-rw-r--r--src/writer.c32
-rw-r--r--test/test_reader_writer.c21
-rw-r--r--test/test_writer.c13
16 files changed, 130 insertions, 105 deletions
diff --git a/NEWS b/NEWS
index f4b060cc..8c6ce835 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
serd (1.1.1) unstable; urgency=medium
* Add SerdBuffer for mutable buffers to keep SerdChunk const-correct
+ * Bring read/write interface closer to C standard
* Make nodes opaque
* Remove SERD_DISABLE_DEPRECATED and SERD_DEPRECATED_BY
* Remove serd_uri_to_path()
diff --git a/include/serd/buffer.h b/include/serd/buffer.h
index 90b51a48..f1bfa897 100644
--- a/include/serd/buffer.h
+++ b/include/serd/buffer.h
@@ -28,14 +28,15 @@ typedef struct {
/**
A convenience sink function for writing to a string.
- This function can be used as a #SerdSink to write to a SerdBuffer which is
- resized as necessary with realloc(). The `stream` parameter must point to
+ This function can be used as a #SerdWriteFunc to write to a SerdBuffer which
+ is resized as necessary with realloc(). The `stream` parameter must point to
an initialized #SerdBuffer. When the write is finished, the string should be
retrieved with serd_buffer_sink_finish().
*/
SERD_API size_t
serd_buffer_sink(const void* SERD_NONNULL buf,
- size_t len,
+ size_t size,
+ size_t nmemb,
void* SERD_NONNULL stream);
/**
diff --git a/include/serd/reader.h b/include/serd/reader.h
index e4bd9b2f..63c2c5ac 100644
--- a/include/serd/reader.h
+++ b/include/serd/reader.h
@@ -113,7 +113,7 @@ serd_reader_start_stream(SerdReader* SERD_NONNULL reader,
*/
SERD_API SerdStatus
serd_reader_start_source_stream(SerdReader* SERD_NONNULL reader,
- SerdSource SERD_NONNULL read_func,
+ SerdReadFunc SERD_NONNULL read_func,
SerdStreamErrorFunc SERD_NONNULL error_func,
void* SERD_NONNULL stream,
const char* SERD_NULLABLE name,
@@ -143,7 +143,7 @@ serd_reader_read_file_handle(SerdReader* SERD_NONNULL reader,
/// Read a user-specified byte source
SERD_API SerdStatus
serd_reader_read_source(SerdReader* SERD_NONNULL reader,
- SerdSource SERD_NONNULL source,
+ SerdReadFunc SERD_NONNULL source,
SerdStreamErrorFunc SERD_NONNULL error,
void* SERD_NONNULL stream,
const char* SERD_NULLABLE name,
diff --git a/include/serd/stream.h b/include/serd/stream.h
index 8b023add..992db552 100644
--- a/include/serd/stream.h
+++ b/include/serd/stream.h
@@ -32,26 +32,38 @@ SERD_BEGIN_DECLS
typedef int (*SerdStreamErrorFunc)(void* SERD_NONNULL stream);
/**
- Source function for raw string input.
+ Function for reading input bytes from a stream.
- Identical semantics to `fread`, but may set errno for more informative error
- reporting than supported by SerdStreamErrorFunc.
+ This has identical semantics to `fread`, but may set `errno` for more
+ informative error reporting than supported by #SerdStreamErrorFunc.
@param buf Output buffer.
@param size Size of a single element of data in bytes (always 1).
@param nmemb Number of elements to read.
@param stream Stream to read from (FILE* for fread).
- @return Number of elements (bytes) read.
+ @return Number of elements (bytes) read, which is short on error.
*/
-typedef size_t (*SerdSource)(void* SERD_NONNULL buf,
- size_t size,
- size_t nmemb,
- void* SERD_NONNULL stream);
-
-/// Sink function for raw string output
-typedef size_t (*SerdSink)(const void* SERD_NONNULL buf,
- size_t len,
- void* SERD_NONNULL stream);
+typedef size_t (*SerdReadFunc)(void* SERD_NONNULL buf,
+ size_t size,
+ size_t nmemb,
+ void* SERD_NONNULL stream);
+
+/**
+ Function for writing output bytes to a stream.
+
+ This has identical semantics to `fwrite`, but may set `errno` for more
+ informative error reporting than supported by #SerdStreamErrorFunc.
+
+ @param buf Input buffer.
+ @param size Size of a single element of data in bytes (always 1).
+ @param nmemb Number of elements to read.
+ @param stream Stream to write to (FILE* for fread).
+ @return Number of elements (bytes) written, which is short on error.
+*/
+typedef size_t (*SerdWriteFunc)(const void* SERD_NONNULL buf,
+ size_t size,
+ size_t nmemb,
+ void* SERD_NONNULL stream);
/**
@}
diff --git a/include/serd/uri.h b/include/serd/uri.h
index 7b5529dc..93409075 100644
--- a/include/serd/uri.h
+++ b/include/serd/uri.h
@@ -133,9 +133,9 @@ serd_uri_is_within(SerdURIView r, SerdURIView base);
@return The number of bytes written.
*/
SERD_API size_t
-serd_write_uri(SerdURIView uri,
- SerdSink SERD_NONNULL sink,
- void* SERD_NONNULL stream);
+serd_write_uri(SerdURIView uri,
+ SerdWriteFunc SERD_NONNULL sink,
+ void* SERD_NONNULL stream);
/**
@}
diff --git a/include/serd/writer.h b/include/serd/writer.h
index 976ed5b7..94747309 100644
--- a/include/serd/writer.h
+++ b/include/serd/writer.h
@@ -13,7 +13,6 @@
#include "serd/stream.h"
#include "serd/syntax.h"
-#include <stddef.h>
#include <stdint.h>
SERD_BEGIN_DECLS
@@ -48,11 +47,11 @@ typedef uint32_t SerdWriterFlags;
/// Create a new RDF writer
SERD_API SerdWriter* SERD_ALLOCATED
-serd_writer_new(SerdSyntax syntax,
- SerdWriterFlags flags,
- SerdEnv* SERD_NONNULL env,
- SerdSink SERD_NONNULL ssink,
- void* SERD_NULLABLE stream);
+serd_writer_new(SerdSyntax syntax,
+ SerdWriterFlags flags,
+ SerdEnv* SERD_NONNULL env,
+ SerdWriteFunc SERD_NONNULL ssink,
+ void* SERD_NULLABLE stream);
/// Free `writer`
SERD_API void
@@ -63,17 +62,6 @@ SERD_PURE_API SerdEnv* SERD_NONNULL
serd_writer_env(SerdWriter* SERD_NONNULL writer);
/**
- A convenience sink function for writing to a FILE*.
-
- This function can be used as a #SerdSink when writing to a FILE*. The
- `stream` parameter must be a FILE* opened for writing.
-*/
-SERD_API size_t
-serd_file_sink(const void* SERD_NONNULL buf,
- size_t len,
- void* SERD_NONNULL stream);
-
-/**
Set a function to be called when errors occur during writing.
The `error_func` will be called with `handle` as its first argument. If
diff --git a/src/byte_sink.h b/src/byte_sink.h
index 0f3d35f5..d033f227 100644
--- a/src/byte_sink.h
+++ b/src/byte_sink.h
@@ -13,15 +13,15 @@
#include <string.h>
typedef struct SerdByteSinkImpl {
- SerdSink sink;
- void* stream;
- char* buf;
- size_t size;
- size_t block_size;
+ SerdWriteFunc sink;
+ void* stream;
+ char* buf;
+ size_t size;
+ size_t block_size;
} SerdByteSink;
static inline SerdByteSink
-serd_byte_sink_new(SerdSink sink, void* stream, size_t block_size)
+serd_byte_sink_new(SerdWriteFunc sink, void* stream, size_t block_size)
{
SerdByteSink bsink;
bsink.sink = sink;
@@ -38,7 +38,7 @@ serd_byte_sink_flush(SerdByteSink* bsink)
{
if (bsink->block_size > 1 && bsink->size > 0) {
const size_t size = bsink->size;
- const size_t n_out = bsink->sink(bsink->buf, size, bsink->stream);
+ const size_t n_out = bsink->sink(bsink->buf, 1, bsink->size, bsink->stream);
bsink->size = 0;
return (n_out != size) ? SERD_BAD_WRITE : SERD_SUCCESS;
@@ -63,7 +63,7 @@ serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* bsink)
}
if (bsink->block_size == 1) {
- return bsink->sink(buf, len, bsink->stream);
+ return bsink->sink(buf, 1, len, bsink->stream);
}
const size_t orig_len = len;
@@ -79,7 +79,7 @@ serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* bsink)
// Flush page if buffer is full
if (bsink->size == bsink->block_size) {
- bsink->sink(bsink->buf, bsink->block_size, bsink->stream);
+ bsink->sink(bsink->buf, 1, bsink->block_size, bsink->stream);
bsink->size = 0;
}
}
diff --git a/src/byte_source.c b/src/byte_source.c
index 54b0ad7e..3a2f10b6 100644
--- a/src/byte_source.c
+++ b/src/byte_source.c
@@ -33,7 +33,7 @@ serd_byte_source_page(SerdByteSource* const source)
SerdStatus
serd_byte_source_open_source(SerdByteSource* const source,
- const SerdSource read_func,
+ const SerdReadFunc read_func,
const SerdStreamErrorFunc error_func,
void* const stream,
const char* const name,
diff --git a/src/byte_source.h b/src/byte_source.h
index e8ddb98a..5290dca2 100644
--- a/src/byte_source.h
+++ b/src/byte_source.h
@@ -21,7 +21,7 @@ typedef struct {
} Cursor;
typedef struct {
- SerdSource read_func; ///< Read function (e.g. fread)
+ SerdReadFunc read_func; ///< Read function (e.g. fread)
SerdStreamErrorFunc error_func; ///< Error function (e.g. ferror)
void* stream; ///< Stream (e.g. FILE)
size_t page_size; ///< Number of bytes to read at a time
@@ -44,7 +44,7 @@ serd_byte_source_open_string(SerdByteSource* source, const char* utf8);
SerdStatus
serd_byte_source_open_source(SerdByteSource* source,
- SerdSource read_func,
+ SerdReadFunc read_func,
SerdStreamErrorFunc error_func,
void* stream,
const char* name,
diff --git a/src/node.c b/src/node.c
index 199fbc5e..5b5b754f 100644
--- a/src/node.c
+++ b/src/node.c
@@ -56,7 +56,7 @@ static const SerdNodeFlags meta_mask = (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE);
static SerdNode*
serd_new_from_uri(SerdURIView uri, SerdURIView base);
-SERD_PURE_FUNC static size_t
+static size_t
serd_uri_string_length(const SerdURIView* const uri)
{
size_t len = uri->path_prefix.length;
@@ -76,12 +76,15 @@ serd_uri_string_length(const SerdURIView* const uri)
}
static size_t
-string_sink(const void* const buf, const size_t len, void* const stream)
+string_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
{
char** ptr = (char**)stream;
- memcpy(*ptr, buf, len);
- *ptr += len;
- return len;
+ memcpy(*ptr, buf, size * nmemb);
+ *ptr += size * nmemb;
+ return nmemb;
}
SERD_PURE_FUNC static size_t
@@ -428,18 +431,18 @@ serd_new_file_uri(const SerdStringView path, const SerdStringView hostname)
SerdBuffer buffer = {uri, uri_len};
for (size_t i = 0; i < path.length; ++i) {
if (path.data[i] == '%') {
- serd_buffer_sink("%%", 2, &buffer);
+ serd_buffer_sink("%%", 1, 2, &buffer);
} else if (is_uri_path_char(path.data[i])) {
- serd_buffer_sink(path.data + i, 1, &buffer);
+ serd_buffer_sink(path.data + i, 1, 1, &buffer);
#ifdef _WIN32
} else if (path.data[i] == '\\') {
- serd_buffer_sink("/", 1, &buffer);
+ serd_buffer_sink("/", 1, 1, &buffer);
#endif
} else {
char escape_str[10] = {'%', 0, 0, 0, 0, 0, 0, 0, 0, 0};
snprintf(
escape_str + 1, sizeof(escape_str) - 1, "%X", (unsigned)path.data[i]);
- serd_buffer_sink(escape_str, 3, &buffer);
+ serd_buffer_sink(escape_str, 1, 3, &buffer);
}
}
diff --git a/src/reader.c b/src/reader.c
index 02738cd2..c7919ca6 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -303,7 +303,7 @@ serd_reader_start_stream(SerdReader* const reader,
const bool bulk)
{
return serd_reader_start_source_stream(reader,
- bulk ? (SerdSource)fread
+ bulk ? (SerdReadFunc)fread
: serd_file_read_byte,
(SerdStreamErrorFunc)ferror,
file,
@@ -313,7 +313,7 @@ serd_reader_start_stream(SerdReader* const reader,
SerdStatus
serd_reader_start_source_stream(SerdReader* const reader,
- const SerdSource read_func,
+ const SerdReadFunc read_func,
const SerdStreamErrorFunc error_func,
void* const stream,
const char* const name,
@@ -369,7 +369,7 @@ serd_reader_read_file_handle(SerdReader* const reader,
const char* const name)
{
return serd_reader_read_source(reader,
- (SerdSource)fread,
+ (SerdReadFunc)fread,
(SerdStreamErrorFunc)ferror,
file,
name,
@@ -378,7 +378,7 @@ serd_reader_read_file_handle(SerdReader* const reader,
SerdStatus
serd_reader_read_source(SerdReader* const reader,
- const SerdSource source,
+ const SerdReadFunc source,
const SerdStreamErrorFunc error,
void* const stream,
const char* const name,
diff --git a/src/serdi.c b/src/serdi.c
index cdd3a7b1..e3b41204 100644
--- a/src/serdi.c
+++ b/src/serdi.c
@@ -11,6 +11,7 @@
#include "serd/reader.h"
#include "serd/sink.h"
#include "serd/status.h"
+#include "serd/stream.h"
#include "serd/string_view.h"
#include "serd/syntax.h"
#include "serd/uri.h"
@@ -343,8 +344,8 @@ main(int argc, char** argv)
SerdEnv* const env =
serd_env_new(base ? serd_node_string_view(base) : serd_empty_string());
- SerdWriter* const writer =
- serd_writer_new(output_syntax, writer_flags, env, serd_file_sink, out_fd);
+ SerdWriter* writer = serd_writer_new(
+ output_syntax, writer_flags, env, (SerdWriteFunc)fwrite, out_fd);
SerdReader* const reader =
serd_reader_new(input_syntax,
diff --git a/src/uri.c b/src/uri.c
index eec9c7fc..0c0f3736 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -48,19 +48,19 @@ serd_parse_file_uri(const char* const uri, char** const hostname)
for (const char* s = path; *s; ++s) {
if (*s == '%') {
if (*(s + 1) == '%') {
- serd_buffer_sink("%", 1, &buffer);
+ serd_buffer_sink("%", 1, 1, &buffer);
++s;
} else if (is_hexdig(*(s + 1)) && is_hexdig(*(s + 2))) {
const uint8_t hi = hex_digit_value((const uint8_t)s[1]);
const uint8_t lo = hex_digit_value((const uint8_t)s[2]);
const char c = (char)((hi << 4U) | lo);
- serd_buffer_sink(&c, 1, &buffer);
+ serd_buffer_sink(&c, 1, 1, &buffer);
s += 2;
} else {
s += 2; // Junk escape, ignore
}
} else {
- serd_buffer_sink(s, 1, &buffer);
+ serd_buffer_sink(s, 1, 1, &buffer);
}
}
@@ -398,48 +398,49 @@ serd_uri_is_within(const SerdURIView uri, const SerdURIView base)
/// See http://tools.ietf.org/html/rfc3986#section-5.3
size_t
-serd_write_uri(const SerdURIView uri, SerdSink sink, void* const stream)
+serd_write_uri(const SerdURIView uri,
+ const SerdWriteFunc sink,
+ void* const stream)
{
size_t len = 0;
if (uri.scheme.data) {
- len += sink(uri.scheme.data, uri.scheme.length, stream);
- len += sink(":", 1, stream);
+ len += sink(uri.scheme.data, 1, uri.scheme.length, stream);
+ len += sink(":", 1, 1, stream);
}
if (uri.authority.data) {
- len += sink("//", 2, stream);
- len += sink(uri.authority.data, uri.authority.length, stream);
+ len += sink("//", 1, 2, stream);
+ len += sink(uri.authority.data, 1, uri.authority.length, stream);
if (uri.authority.length > 0 && uri_path_len(&uri) > 0 &&
uri_path_at(&uri, 0) != '/') {
// Special case: ensure path begins with a slash
// https://tools.ietf.org/html/rfc3986#section-3.2
- len += sink("/", 1, stream);
+ len += sink("/", 1, 1, stream);
}
}
if (uri.path_prefix.data) {
- len += sink(uri.path_prefix.data, uri.path_prefix.length, stream);
+ len += sink(uri.path_prefix.data, 1, uri.path_prefix.length, stream);
} else if (uri.path_prefix.length) {
for (size_t i = 0; i < uri.path_prefix.length; ++i) {
- len += sink("../", 3, stream);
+ len += sink("../", 1, 3, stream);
}
}
if (uri.path.data) {
- len += sink(uri.path.data, uri.path.length, stream);
+ len += sink(uri.path.data, 1, uri.path.length, stream);
}
if (uri.query.data) {
- len += sink("?", 1, stream);
- len += sink(uri.query.data, uri.query.length, stream);
+ len += sink("?", 1, 1, stream);
+ len += sink(uri.query.data, 1, uri.query.length, stream);
}
if (uri.fragment.data) {
// Note that uri.fragment.data includes the leading '#'
- len += sink(uri.fragment.data, uri.fragment.length, stream);
+ len += sink(uri.fragment.data, 1, uri.fragment.length, stream);
}
-
return len;
}
diff --git a/src/writer.c b/src/writer.c
index cea75aec..01beb315 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -23,6 +23,7 @@
#include "serd/uri.h"
#include "serd/writer.h"
+#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -553,12 +554,15 @@ typedef struct {
} UriSinkContext;
SERD_NODISCARD static size_t
-uri_sink(const void* buf, size_t len, void* stream)
+uri_sink(const void* buf, size_t size, size_t nmemb, void* stream)
{
+ (void)size;
+ assert(size == 1);
+
UriSinkContext* const context = (UriSinkContext*)stream;
SerdWriter* const writer = context->writer;
- return write_uri(writer, (const char*)buf, len, &context->status);
+ return write_uri(writer, (const char*)buf, nmemb, &context->status);
}
SERD_NODISCARD static SerdStatus
@@ -1126,7 +1130,7 @@ SerdWriter*
serd_writer_new(SerdSyntax syntax,
SerdWriterFlags flags,
SerdEnv* env,
- SerdSink ssink,
+ SerdWriteFunc ssink,
void* stream)
{
const WriteContext context = WRITE_CONTEXT_NULL;
@@ -1262,27 +1266,27 @@ serd_writer_env(SerdWriter* writer)
}
size_t
-serd_file_sink(const void* buf, size_t len, void* stream)
+serd_buffer_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
{
- return fwrite(buf, 1, len, (FILE*)stream);
-}
+ assert(size == 1);
+ (void)size;
-size_t
-serd_buffer_sink(const void* const buf, const size_t len, void* const stream)
-{
SerdBuffer* buffer = (SerdBuffer*)stream;
- char* new_buf = (char*)realloc((char*)buffer->buf, buffer->len + len);
+ char* new_buf = (char*)realloc(buffer->buf, buffer->len + nmemb);
if (new_buf) {
- memcpy(new_buf + buffer->len, buf, len);
+ memcpy(new_buf + buffer->len, buf, nmemb);
buffer->buf = new_buf;
- buffer->len += len;
+ buffer->len += nmemb;
}
- return len;
+ return nmemb;
}
char*
serd_buffer_sink_finish(SerdBuffer* const stream)
{
- serd_buffer_sink("", 1, stream);
+ serd_buffer_sink("", 1, 1, stream);
return (char*)stream->buf;
}
diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c
index 9183af5c..3b656c2e 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -374,21 +374,27 @@ test_read_string(void)
}
static size_t
-faulty_sink(const void* const buf, const size_t len, void* const stream)
+faulty_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
{
(void)buf;
- (void)len;
+ (void)size;
+ (void)nmemb;
+
+ assert(size == 1);
ErrorContext* const ctx = (ErrorContext*)stream;
- const size_t new_n_written = ctx->n_written + len;
+ const size_t new_n_written = ctx->n_written + nmemb;
if (new_n_written >= ctx->error_offset) {
errno = EINVAL;
return 0U;
}
- ctx->n_written += len;
+ ctx->n_written += nmemb;
errno = 0;
- return len;
+ return nmemb;
}
static SerdStatus
@@ -448,7 +454,8 @@ test_writer(const char* const path)
SerdEnv* env = serd_env_new(serd_empty_string());
assert(fd);
- SerdWriter* writer = serd_writer_new(SERD_TURTLE, 0, env, serd_file_sink, fd);
+ SerdWriter* writer =
+ serd_writer_new(SERD_TURTLE, 0, env, (SerdWriteFunc)fwrite, fd);
assert(writer);
serd_writer_chop_blank_prefix(writer, "tmp");
@@ -595,7 +602,7 @@ test_reader(const char* path)
{
size_t n_reads = 0;
serd_reader_start_source_stream(reader,
- (SerdSource)eof_test_read,
+ (SerdReadFunc)eof_test_read,
(SerdStreamErrorFunc)eof_test_error,
&n_reads,
NULL,
diff --git a/test/test_writer.c b/test/test_writer.c
index 76d046d7..0c78495e 100644
--- a/test/test_writer.c
+++ b/test/test_writer.c
@@ -77,12 +77,15 @@ test_write_long_literal(void)
}
static size_t
-null_sink(const void* const buf, const size_t len, void* const stream)
+null_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
{
(void)buf;
(void)stream;
- return len;
+ return size * nmemb;
}
static void
@@ -167,9 +170,13 @@ test_strict_write(void)
// Produce a write error without setting errno
static size_t
-error_sink(const void* const buf, const size_t len, void* const stream)
+error_sink(const void* const buf,
+ const size_t size,
+ const size_t len,
+ void* const stream)
{
(void)buf;
+ (void)size;
(void)len;
(void)stream;
return 0U;